/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 Gary Mills
*
*/
/*
* Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/ethernet.h>
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
#include <sys/sysmacros.h>
#include <sys/dditypes.h>
#include <sys/byteorder.h>
#include "atge.h"
#include "atge_cmn_reg.h"
#include "atge_l1c_reg.h"
#include "atge_l1e_reg.h"
#include "atge_l1_reg.h"
/*
* L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
* flavors only. L1C comes in both flavours.
*
* with an exception of L1E. L1E's RX side is not descriptor based ring.
* The L1E's RX uses pages (not to be confused with MMU pages) for
* receiving pkts. The header has four fields :
*
* uint32_t seqno; Sequence number of the frame.
* uint32_t length; Length of the frame.
* uint32_t flags; Flags
* uint32_t vtag; We don't use hardware VTAG.
*
* We use only one queue for RX (each queue can have two pages) and each
* page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
* use zero-copy RX because we are limited to two pages and each page
* accomodates large number of pkts.
*
* The TX side on all three chips is descriptor based ring; and all the
* more reason to have one driver for these chips.
*
* We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
* should be held if the operation has impact on the driver instance.
*
* All the three chips have hash-based multicast filter.
*
* We use CMB (Coalescing Message Block) for RX but not for TX as there
* are some issues with TX. RX CMB is used to get the last descriptor
* posted by the chip. Each CMB is for a RX page (one queue can have two
* pages) and are uint32_t (4 bytes) long.
*
* The descriptor table should have 32-bit physical address limit due to
*
* kept sgl as 1 so that we get contingous pages from root complex.
*
* L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
* common with L1E chip (0x1026).
*/
/*
* Function Prototypes for debugging.
*/
void atge_error(dev_info_t *, char *, ...);
void atge_debug_func(char *, ...);
/*
* Function Prototypes for driver operations.
*/
static int atge_resume(dev_info_t *);
static int atge_add_intr(atge_t *);
static int atge_alloc_dma(atge_t *);
static void atge_remove_intr(atge_t *);
static void atge_free_dma(atge_t *);
static void atge_device_reset(atge_t *);
static void atge_device_init(atge_t *);
static void atge_device_start(atge_t *);
static void atge_disable_intrs(atge_t *);
void atge_free_a_dma_blk(atge_dma_t *);
static void atge_rxfilter(atge_t *);
static void atge_device_reset_l1_l1e(atge_t *);
void atge_device_restart(atge_t *);
void atge_device_stop(atge_t *);
/*
*/
void atge_l1e_device_reset(atge_t *);
void atge_l1e_stop_mac(atge_t *);
int atge_l1e_alloc_dma(atge_t *);
void atge_l1e_free_dma(atge_t *);
void atge_l1e_init_tx_ring(atge_t *);
void atge_l1e_init_rx_pages(atge_t *);
void atge_l1e_program_dma(atge_t *);
void atge_l1e_send_packet(atge_ring_t *);
void atge_l1e_gather_stats(atge_t *);
void atge_l1e_clear_stats(atge_t *);
/*
* L1 specific functions.
*/
int atge_l1_alloc_dma(atge_t *);
void atge_l1_free_dma(atge_t *);
void atge_l1_init_tx_ring(atge_t *);
void atge_l1_init_rx_ring(atge_t *);
void atge_l1_init_rr_ring(atge_t *);
void atge_l1_init_cmb(atge_t *);
void atge_l1_init_smb(atge_t *);
void atge_l1_program_dma(atge_t *);
void atge_l1_stop_tx_mac(atge_t *);
void atge_l1_stop_rx_mac(atge_t *);
void atge_l1_send_packet(atge_ring_t *);
/*
* L1C specific functions.
*/
int atge_l1c_alloc_dma(atge_t *);
void atge_l1c_free_dma(atge_t *);
void atge_l1c_init_tx_ring(atge_t *);
void atge_l1c_init_rx_ring(atge_t *);
void atge_l1c_init_rr_ring(atge_t *);
void atge_l1c_init_cmb(atge_t *);
void atge_l1c_init_smb(atge_t *);
void atge_l1c_program_dma(atge_t *);
void atge_l1c_stop_tx_mac(atge_t *);
void atge_l1c_stop_rx_mac(atge_t *);
void atge_l1c_send_packet(atge_ring_t *);
void atge_l1c_gather_stats(atge_t *);
void atge_l1c_clear_stats(atge_t *);
/*
* Function prototyps for MII operations.
*/
void atge_l1e_mii_reset(void *);
void atge_l1_mii_reset(void *);
void atge_l1c_mii_reset(void *);
static void atge_mii_notify(void *, link_state_t);
/*
*/
};
/*
* L1 chip.
*/
};
/*
* L1C chip.
*/
};
/*
* Function Prototypes for MAC callbacks.
*/
static int atge_m_start(void *);
static void atge_m_stop(void *);
void *);
const void *);
static void atge_m_propinfo(void *, const char *, mac_prop_id_t,
static int atge_m_unicst(void *, const uint8_t *);
static int atge_m_promisc(void *, boolean_t);
NULL, /* mc_reserved */
NULL, /* mc_ioctl */
NULL, /* mc_getcapab */
NULL, /* mc_open */
NULL, /* mc_close */
};
/*
* DMA Data access requirements.
*/
};
/*
* Buffers should be native endianness.
*/
DDI_NEVERSWAP_ACC, /* native endianness */
};
/*
* DMA device attributes. Buffer can be 64-bit.
*/
DMA_ATTR_V0, /* dma_attr_version */
0, /* dma_attr_addr_lo */
0x00ffffffffffull, /* dma_attr_addr_hi */
0x000000003fffull, /* dma_attr_count_max */
8, /* dma_attr_align */
0x00003ffc, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0x0000000027ffull, /* dma_attr_maxxfer */
0x0000ffffffffull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
/*
* Table of supported devices.
*/
};
/*
* Global Debugging flag. Developer level debugging is done only in DEBUG mode.
*/
/*
* Debugging and error reporting.
*/
void
{
}
static
void
{
char *p = "!%s%d: %s";
char *q = "!atge: %s";
p++;
q++;
}
if (dip) {
} else {
}
}
void
{
}
void
{
}
void
{
int speed;
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1C:
break;
}
break;
}
switch (speed) {
case 10:
case 100:
break;
case 1000:
break;
}
if (ld == LINK_DUPLEX_FULL)
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
case ATGE_CHIP_L1C:
break;
}
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
/* Configure interrupt moderation timer. */
/*
* We don't want to automatic interrupt clear as task queue
* for the interrupt should know interrupt status.
*/
reg = 0;
break;
}
ATGE_DB(("%s: %s() mac_cfg is : %x",
}
static void
{
ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
/*
* Reconfigure MAC if link status is UP now.
*/
if (link == LINK_STATE_UP) {
atgep->atge_tx_resched = 0;
} else {
}
if (link == LINK_STATE_UP)
}
void
{
uchar_t *c;
int start;
start = r->r_consumer;
return;
r->r_avail_desc++;
if (r->r_avail_desc > ATGE_TX_RING_CNT) {
"Reclaim : TX descriptor error");
break;
}
}
c += (sizeof (atge_tx_desc_t) * start);
txd = (atge_tx_desc_t *)c;
/*
* Clearing TX descriptor helps in debugging some strange
* problems.
*/
}
}
/*
* Adds interrupt handler depending upon the type of interrupt supported by
* the chip.
*/
static int
{
int err;
int count = 0;
int avail = 0;
int i;
int flag;
if (intr_type != DDI_INTR_TYPE_FIXED) {
if (err != DDI_SUCCESS) {
"ddi_intr_get_nintrs failed : %d", err);
return (DDI_FAILURE);
}
ATGE_DB(("%s: %s() count : %d",
if (err != DDI_SUCCESS) {
"ddi_intr_get_navail failed : %d", err);
return (DDI_FAILURE);
}
}
} else {
/*
* DDI_INTR_TYPE_FIXED case.
*/
count = 1;
avail = 1;
}
ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
intr_type));
if (err != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
&atgep->atge_intr_pri);
if (err != DDI_SUCCESS) {
for (i = 0; i < atgep->atge_intr_cnt; i++) {
}
return (DDI_FAILURE);
}
/*
* Add interrupt handler now.
*/
for (i = 0; i < atgep->atge_intr_cnt; i++) {
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
if (err != DDI_SUCCESS) {
"ddi_intr_add_handler failed : %d", err);
while (--i >= 0) {
(void) ddi_intr_remove_handler(
atgep->atge_intr_handle[i]);
(void) ddi_intr_free(
atgep->atge_intr_handle[i]);
}
return (DDI_FAILURE);
}
}
&atgep->atge_intr_cap);
if (err != DDI_SUCCESS) {
"ddi_intr_get_cap failed : %d", err);
return (DDI_FAILURE);
}
if (intr_type == DDI_INTR_TYPE_FIXED)
else if (intr_type == DDI_INTR_TYPE_MSI)
else if (intr_type == DDI_INTR_TYPE_MSIX)
return (DDI_SUCCESS);
}
void
{
int i;
int cap = 0;
return;
cap = 1;
}
for (i = 0; i < atgep->atge_intr_cnt; i++) {
if (cap == 0)
}
}
int
{
int err;
int i;
/*
* Do block enable.
*/
if (err != DDI_SUCCESS) {
"Failed to block enable intrs %d", err);
err = DDI_FAILURE;
} else {
err = DDI_SUCCESS;
}
} else {
/*
* Call ddi_intr_enable() for MSI non-block enable.
*/
for (i = 0; i < atgep->atge_intr_cnt; i++) {
if (err != DDI_SUCCESS) {
"Failed to enable intrs on %d with : %d",
i, err);
break;
}
}
if (err == DDI_SUCCESS)
err = DDI_SUCCESS;
else
err = DDI_FAILURE;
}
return (err);
}
/*
* Adds interrupt handler depending on the supported interrupt type by the
* chip.
*/
static int
{
int err;
/*
* Get the supported interrupt types.
*/
&atgep->atge_intr_types);
if (err != DDI_SUCCESS) {
"ddi_intr_get_supported_types failed : %d", err);
return (DDI_FAILURE);
}
ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
if (err == DDI_SUCCESS) {
ATGE_DB(("%s: Using MSIx for interrupt",
return (err);
}
}
if (err == DDI_SUCCESS) {
ATGE_DB(("%s: Using MSI for interrupt",
return (err);
}
}
err = DDI_FAILURE;
if (err == DDI_SUCCESS) {
ATGE_DB(("%s: Using FIXED type for interrupt",
return (err);
}
}
return (err);
}
int
{
int i;
atgep->atge_model = 0;
for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
atgep->atge_revid =
atge_cards[i].cardname);
ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
atgep->atge_model));
return (DDI_SUCCESS);
}
}
/*
* Assume it's L1C chip.
*/
/*
* We will leave the decision to caller.
*/
return (DDI_FAILURE);
}
int
{
if ((reg & SPI_VPD_ENB) != 0) {
/*
* Get VPD stored in TWSI EEPROM.
*/
reg &= ~SPI_VPD_ENB;
}
ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
atgep->atge_ether_addr[0],
return (DDI_SUCCESS);
}
/*
* Reset functionality for L1, L1E, and L1C. It's same.
*/
static void
{
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
case ATGE_CHIP_L1:
case ATGE_CHIP_L1C:
break;
}
}
void
{
int t;
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1C:
break;
default:
break;
}
for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
drv_usecwait(10);
if ((reg & MASTER_RESET) == 0)
break;
}
if (t == 0) {
reg);
}
for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
break;
drv_usecwait(10);
}
if (t == 0) {
reg);
}
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
case ATGE_CHIP_L1:
/*
* Initialize PCIe module. These values came from FreeBSD and
* we don't know the meaning of it.
*/
break;
case ATGE_CHIP_L1C:
break;
}
/*
* Get chip revision.
*/
}
/*
* DMA allocation for L1 and L1E is bit different since L1E uses RX pages
* instead of descriptor based RX model.
*/
static int
{
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
return (err);
}
static void
{
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
}
/*
* Attach entry point in the driver.
*/
static int
{
int instance;
int err;
switch (cmd) {
case DDI_RESUME:
return (atge_resume(devinfo));
case DDI_ATTACH:
break;
default:
return (DDI_FAILURE);
}
/*
* Setup name and instance number to be used for debugging and
* error reporting.
*/
"atge", instance);
/*
* Map PCI config space.
*/
if (err != DDI_SUCCESS) {
goto fail1;
}
(void) atge_identify_hardware(atgep);
/*
* Map Device registers.
*/
if (err != DDI_SUCCESS) {
goto fail2;
}
/*
* Add interrupt and its associated handler.
*/
if (err != DDI_SUCCESS) {
goto fail3;
}
/*
* Used to lock down MBOX register on L1 chip since RX consumer,
* TX producer and RX return ring consumer are shared.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
/* L2E Rev. B. AR8114 */
} else {
PHY_STATUS_100M) != 0) {
/* L1E AR8121 */
} else {
/* L2E Rev. A. AR8113 */
}
}
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
/*
* One odd thing is AR8132 uses the same PHY hardware(F1
* gigabit PHY) of AR8131. So atphy(4) of AR8132 reports
* the PHY supports 1000Mbps but that's not true. The PHY
* used in AR8132 can't establish gigabit link even if it
*
* addition, Atheros said that enabling SMB wouldn't improve
* performance. However I think it's bad to access lots of
* registers to extract MAC statistics.
*
* Don't use Tx CMB. It is known to have silicon bug.
*/
break;
break;
case ATGE_CHIP_L1CF_DEV_ID:
break;
case ATGE_CHIP_L1CG_DEV_ID:
break;
}
break;
}
/*
* Get DMA parameters from PCIe device control register.
*/
&cap_ptr);
if (err == DDI_FAILURE) {
} else {
cap_ptr + 0x08);
/*
* Max read request size.
*/
/*
* Max Payload Size.
*/
ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
}
/* Clear data link and flow-control protocol error. */
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
/*
* Allocate DMA resources.
*/
if (err != DDI_SUCCESS) {
goto fail4;
}
/*
* Get station address.
*/
(void) atge_get_macaddr(atgep);
/*
* Setup MII.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
goto fail4;
}
/*
* Register with MAC layer.
*/
goto fail4;
}
goto fail4;
}
ATGE_DB(("%s: %s() driver attached successfully",
/*
* At last - enable interrupts.
*/
if (err == DDI_FAILURE) {
goto fail5;
}
/*
* Reset the PHY before starting.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
/*
* Let the PHY run.
*/
return (DDI_SUCCESS);
if (atgep)
return (DDI_FAILURE);
}
static int
{
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
/*
* First unregister with MAC layer before stopping DMA
*/
return (DDI_FAILURE);
return (DDI_SUCCESS);
case DDI_SUSPEND:
ATGE_DB(("%s: %s() is being suspended",
/*
* Suspend monitoring MII.
*/
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
int
{
int i;
for (i = 0; i < rcnt; i++) {
err = DDI_FAILURE;
break;
}
}
return (err);
}
void
{
int i;
return;
for (i = 0; i < rcnt; i++) {
atge_buf_free(tbl[i]);
}
}
}
{
int err;
if (err != DDI_SUCCESS) {
goto fail;
}
if (err != DDI_SUCCESS) {
goto fail;
}
if (err != DDI_SUCCESS) {
goto fail;
}
return (dma);
fail:
return (NULL);
}
void
{
}
}
{
int err;
if (err != DDI_SUCCESS) {
goto fail;
}
if (err != DDI_SUCCESS) {
goto fail;
}
if (err != DDI_SUCCESS) {
goto fail;
}
/*
* Number of return'ed cookie should be one.
*/
return (dma);
fail:
return (NULL);
}
void
{
}
static int
{
return (DDI_FAILURE);
}
} else {
}
/*
* Reset the PHY before resuming MII.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
/* kick-off downstream */
return (DDI_SUCCESS);
}
static int
{
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
{
int bit;
ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
" atge_mchash_ref_cnt[bit] :%d",
}
void
{
int bit;
ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
" atge_mchash_ref_cnt[bit] :%d",
}
int
{
if (add) {
} else {
}
return (0);
}
int
{
if (on) {
} else {
}
}
return (0);
}
int
{
return (0);
}
mblk_t *
{
/*
* This NIC does not like us to send pkt when link is down.
*/
return (mp);
}
/*
* Don't send a pkt if chip isn't running or in suspended state.
*/
return (mp);
}
break;
}
}
return (mp);
}
int
{
int started = 0;
started = 1;
}
/* kick-off downstream */
if (started)
return (0);
}
void
{
/*
* Cancel any pending I/O.
*/
}
int
{
return (0);
}
switch (stat) {
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_NORCVBUF:
break;
case MAC_STAT_NOXMTBUF:
*val = 0;
break;
case MAC_STAT_COLLISIONS:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_OERRORS:
break;
case ETHER_STAT_ALIGN_ERRORS:
break;
case ETHER_STAT_FCS_ERRORS:
break;
case ETHER_STAT_SQE_ERRORS:
break;
case ETHER_STAT_DEFER_XMTS:
break;
break;
break;
break;
case ETHER_STAT_EX_COLLISIONS:
break;
case ETHER_STAT_MACXMT_ERRORS:
break;
break;
break;
case ETHER_STAT_MACRCV_ERRORS:
break;
case MAC_STAT_OVERFLOWS:
break;
case MAC_STAT_UNDERFLOWS:
break;
break;
case ETHER_STAT_JABBER_ERRORS:
break;
default:
return (ENOTSUP);
}
return (0);
}
int
void *val)
{
}
int
const void *val)
{
int r;
if (r == 0) {
}
}
return (r);
}
static void
{
}
void
{
ether_addr_t e;
/*
* Reprogram the Station address.
*/
((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
}
/*
* Device specific operations.
*/
void
{
/*
* Reprogram the Station address.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
__func__));
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
/*
* Disable interrupt re-trigger timer. We don't want automatic
* re-triggering of un-ACKed interrupts.
*/
/* Configure CMB. */
/*
* Hardware can be configured to issue SMB interrupt based
* on programmed interval. Since there is a callout that is
* invoked for every hz in driver we use that instead of
* relying on periodic SMB interrupt.
*/
/* Clear MAC statistics. */
break;
}
/*
* Set Maximum frame size but don't let MTU be less than ETHER_MTU.
*/
else
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
/* Disable header split(?) */
break;
}
/*
*/
/*
* Set parameters for half-duplex media.
*/
/*
* Configure jumbo frame.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
else
}
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
/*
* Configure flow-control parameters.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
case ATGE_CHIP_L1:
/*
* Some hardware version require this magic.
*/
}
break;
case ATGE_CHIP_L1C:
break;
}
/*
* These are all magic parameters which came from FreeBSD.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
break;
case ATGE_CHIP_L1:
switch (atgep->atge_chip_rev) {
case 0x8001:
case 0x9001:
case 0x9002:
case 0x9003:
break;
default:
if (rxf_lo > 192)
rxf_lo = 192;
if (rrd_lo > 2)
rrd_lo = 2;
break;
}
((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
break;
case ATGE_CHIP_L1C:
break;
case ATGE_CHIP_L1CG_DEV_ID:
case ATGE_CHIP_L1CF_DEV_ID:
/*
* Configure flow control parameters.
* XON : 80% of Rx FIFO
* XOFF : 30% of Rx FIFO
*/
((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
break;
}
break;
}
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
/* Configure RxQ. */
/*
* Configure TxQ.
*/
reg = (128 <<
/* Disable RSS. */
/*
* Configure DMA parameters.
*/
/*
* Don't use Tx CMB. It is known to cause RRS update failure
* under certain circumstances. Typical phenomenon of the
* issue would be unexpected sequence number encountered in
* Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
*/
/*
*/
break;
case ATGE_CHIP_L1:
/* Configure RxQ. */
reg =
/*
* Configure TxQ.
*/
reg =
/* Jumbo frames */
/*
* Configure DMA parameters.
*/
/* Configure CMB DMA write threshold. */
/*
*/
/* Request SMB updates for every seconds. */
break;
case ATGE_CHIP_L1C:
/* Configure RxQ. */
reg =
/*
* Configure TxQ.
*/
reg = (128 <<
reg >>= 1;
break;
}
reg |= (L1C_TXQ_CFG_TPD_BURST_DEFAULT <<
/*
* Configure DMA parameters.
*/
/* Configure CMB DMA write threshold not required. */
break;
}
/*
* Disable all WOL bits as WOL can interfere normal Rx
* operation.
*/
/*
* - Auto-padding for short frames.
* - Enable CRC generation.
*
* Start with full-duplex/1000Mbps media. Actual reconfiguration
* of MAC is followed after link establishment.
*/
/*
* of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to
* have bug in protocol field in Rx return structure so
* these controllers can't handle fragmented frames. Disable
* Rx checksum offloading until there is a newer controller
* that has sane implementation.
*/
break;
}
} else {
}
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1C:
break;
}
/*
* Set up the receive filter.
*/
/*
* Acknowledge all pending interrupts and clear it.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
case ATGE_CHIP_L1C:
break;
}
}
/*
* Generic functions.
*/
{
int idx;
int bit;
crc = 0xffffffff;
}
}
return (crc);
}
/*
* Programs RX filter. We use a link-list to keep track of all multicast
* addressess.
*/
void
{
/*
* Accept broadcast frames.
*/
rxcfg |= ATGE_CFG_BCAST;
/*
* We don't use Hardware VLAN tagging.
*/
} else {
}
ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
}
void
{
int t;
/*
* If the chip is being suspended, then don't touch the state. Caller
* will take care of setting the correct state.
*/
}
/*
* Collect stats for L1E. L1 chip's stats are collected by interrupt.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
case ATGE_CHIP_L1C:
break;
}
/*
* Disable interrupts.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
/* Clear CTRL not required. */
/* Stop DMA Engine not required. */
/*
* Disable queue processing.
*/
/* Stop TxQ */
/* Stop RxQ */
/* Stop DMA */
drv_usecwait(1000);
break;
case ATGE_CHIP_L1:
/* Clear CTRL. */
/* Stop DMA Engine */
/*
* Disable queue processing.
*/
/* Stop TxQ */
/* Stop RxQ */
break;
case ATGE_CHIP_L1C:
/* Clear CTRL not required. */
/* Stop DMA Engine */
/*
* Disable queue processing.
*/
/* Stop TxQ */
/* Stop RxQ */
break;
}
for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
break;
drv_usecwait(10);
}
if (t == 0) {
__func__);
}
}
void
{
}
void
{
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
/* Enable all clocks. */
break;
}
}
void
{
/*
* Cancel any pending I/O.
*/
/*
* Reset the chip to a known state.
*/
/*
*/
/*
* Start the chip.
*/
}
static int
{
uchar_t *c;
atge_ring_t *r;
int start;
ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
return (DDI_SUCCESS);
}
r = atgep->atge_tx_ring;
if (r->r_avail_desc <= 1) {
atgep->atge_noxmtbuf++;
ATGE_DB(("%s: %s() No transmit buf",
return (DDI_FAILURE);
}
start = r->r_producer;
/*
* Get the DMA buffer to hold a packet.
*/
/*
* Copy the msg and free mp
*/
r->r_avail_desc--;
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1C:
{
c += (sizeof (l1c_tx_desc_t) * start);
txd = (l1c_tx_desc_t *)c;
cflags |= L1C_TD_EOP;
break;
}
default:
{
c += (sizeof (atge_tx_desc_t) * start);
txd = (atge_tx_desc_t *)c;
cflags |= ATGE_TD_EOP;
break;
}
}
/*
* Sync buffer first.
*/
/*
* Increment TX producer count by one.
*/
/*
* Sync descriptor table.
*/
/*
* Program TX descriptor to send a packet.
*/
switch (ATGE_MODEL(atgep)) {
case ATGE_CHIP_L1E:
break;
case ATGE_CHIP_L1:
break;
case ATGE_CHIP_L1C:
break;
}
r->r_atge->atge_opackets++;
ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer :%d, "
return (DDI_SUCCESS);
}
/*
* Stream Information.
*/
/*
* Module linkage information.
*/
&mod_driverops, /* Type of Module */
&atge_devops /* drv_dev_ops */
};
MODREV_1, /* ml_rev */
(void *)&atge_modldrv,
};
/*
* DDI Entry points.
*/
int
_init(void)
{
int r;
}
return (r);
}
int
_fini(void)
{
int r;
}
return (r);
}
int
{
}