/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2001-2006 Advanced Micro Devices, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* + Redistributions of source code must retain the above copyright notice,
* + this list of conditions and the following disclaimer.
*
* + Redistributions in binary form must reproduce the above copyright
* + notice, this list of conditions and the following disclaimer in the
*
* + Neither the name of Advanced Micro Devices, Inc. nor the names of its
* + contributors may be used to endorse or promote products derived from
* + this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 ADVANCED MICRO DEVICES, INC. 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.
*
* Compliance with Applicable Laws. Notice is hereby given that
* the software may be subject to restrictions on use, release,
* the laws and regulations of the United States or other
* countries ("Applicable Laws"), which include but are not
* limited to U.S. export control laws such as the Export
* Administration Regulations and national security controls as
* defined thereunder, as well as State Department controls under
* redistribute the software is conditioned upon compliance with
* all Applicable Laws, including U.S. export control laws
* regarding specifically designated persons, countries and
* nationals of countries subject to national security controls.
*/
/* include files */
#include "amd8111s_main.h"
/* Global macro Definations */
static char ident[] = "AMD8111 10/100M Ethernet";
/*
* Driver Entry Points
*/
/*
* GLD Entry points prototype
*/
static int amd8111s_m_unicst(void *, const uint8_t *);
static int amd8111s_m_promisc(void *, boolean_t);
static int amd8111s_m_start(void *);
static void amd8111s_m_stop(void *);
static int amd8111s_odlInit(struct LayerPointers *);
static void amd8111s_free_descriptors(struct LayerPointers *);
static void amd8111s_free_dma_ringbuf(struct amd8111s_dma_ringbuf *);
char *fmt, ...);
NULL,
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev /* cb_awrite */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
NULL, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
amd8111s_attach, /* devo_attach */
amd8111s_detach, /* devo_detach */
nodev, /* devo_reset */
&amd8111s_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
nodev, /* devo_power */
ddi_quiesce_not_supported, /* devo_quiesce */
};
&mod_driverops, /* Type of module. This one is a driver */
ident, /* short description */
&amd8111s_dev_ops /* driver specific ops */
};
};
/*
* Global Variables
*/
DMA_ATTR_V0, /* dma_attr_version */
(uint64_t)0, /* dma_attr_addr_lo */
(int)1, /* dma_attr_sgllen */
(uint_t)0 /* dma_attr_flags */
};
DMA_ATTR_V0, /* dma_attr_version */
(uint64_t)0, /* dma_attr_addr_lo */
(int)1, /* dma_attr_sgllen */
(uint_t)0 /* dma_attr_flags */
};
/* PIO access attributes for registers */
};
NULL,
};
/*
* Standard Driver Load Entry Point
* It will be called at load time of driver.
*/
int
_init()
{
int status;
if (status != DDI_SUCCESS) {
}
return (status);
}
/*
* Standard Driver Entry Point for Query.
* It will be called at any time to get Driver info.
*/
int
{
}
/*
* Standard Driver Entry Point for Unload.
* It will be called at unload time of driver.
*/
int
_fini()
{
int status;
if (status == DDI_SUCCESS) {
}
return (status);
}
/*
* Loopback Support
*/
};
static void
{
/*
* If the mode isn't being changed, there's nothing to do ...
*/
return;
/*
* Validate the requested mode and prepare a suitable message
* probably induce ...
*/
switch (mode) {
default:
return;
case AMD8111S_LB_NONE:
INLOOP);
} else {
EXLOOP);
}
break;
case AMD8111S_LB_EXTERNAL_100:
/* Tell GLD the state of the physical link. */
break;
case AMD8111S_LB_EXTERNAL_10:
/* Tell GLD the state of the physical link. */
break;
case AMD8111S_LB_INTERNAL_MAC:
/* Disable Port Manager */
EN_PMGR);
/* Tell GLD the state of the physical link. */
break;
}
/*
* All OK; tell the caller to reprogram
*/
}
static enum ioc_reply
{
int cmd;
/*
* Validate format of ioctl
*/
return (IOC_INVAL);
switch (cmd) {
default:
/* NOTREACHED */
"amd8111s_loop_ioctl: invalid cmd 0x%x", cmd);
return (IOC_INVAL);
case LB_GET_INFO_SIZE:
"wrong LB_GET_INFO_SIZE size");
return (IOC_INVAL);
}
break;
case LB_GET_INFO:
"Wrong LB_GET_INFO size");
return (IOC_INVAL);
}
break;
case LB_GET_MODE:
"Wrong LB_GET_MODE size");
return (IOC_INVAL);
}
break;
case LB_SET_MODE:
"Wrong LB_SET_MODE size");
return (IOC_INVAL);
}
break;
}
return (IOC_REPLY);
}
static void
{
return;
}
case LB_GET_INFO_SIZE:
case LB_GET_INFO:
case LB_GET_MODE:
case LB_SET_MODE:
break;
default:
break;
}
/*
* Decide how to reply
*/
switch (status) {
default:
case IOC_INVAL:
/*
* Error, reply with a NAK and EINVAL or the specified error
*/
break;
case IOC_DONE:
/*
* OK, reply already sent
*/
break;
case IOC_ACK:
/*
* OK, reply with an ACK
*/
break;
case IOC_REPLY:
/*
* OK, send prepared reply as ACK or NAK
*/
break;
}
}
/*
* Copy one packet from dma memory to mblk. Inc dma descriptor pointer.
*/
static boolean_t
{
int length = 0;
->pNonphysical;
sizeof (struct rx_desc), DDI_DMA_SYNC_FORCPU);
if ((descriptor->Rx_OWN) == 0) {
/*
* If the frame is received with errors, then set MCNT
* of that pkt in ReceiveArray to 0. This packet would
* be discarded later and not indicated to OS.
*/
if (descriptor->Rx_ERR) {
statistics->rx_desc_err ++;
descriptor->Rx_ERR = 0;
descriptor->Rx_FRAM = 0;
}
descriptor->Rx_OFLO = 0;
pOdl->rx_overflow_counter ++;
(pOdl->pause_interval == 0)) {
pOdl->rx_overflow_counter = 0;
}
}
descriptor->Rx_CRC = 0;
}
descriptor->Rx_BUFF = 0;
}
goto Next_Descriptor;
}
/* Length of incoming packet */
if (pOdl->rx_fcs_stripped) {
} else {
}
if (length < 62) {
}
statistics->rx_allocfail ++;
goto failed;
}
/* Copy from virtual address of incoming packet */
statistics->rx_ok_packets ++;
} else {
}
descriptor->Rx_MCNT = 0;
descriptor->Rx_SOP = 0;
descriptor->Rx_EOP = 0;
descriptor->Rx_PAM = 0;
descriptor->Rx_BAM = 0;
descriptor->TT = 0;
}
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Get the received packets from NIC card and send them to GLD.
*/
static void
{
int numOfPkts = 0;
if (!pLayerPointers->run) {
return;
}
if (pOdl->pause_interval > 0)
pOdl->pause_interval --;
while (numOfPkts < RX_RING_SIZE) {
break;
}
numOfPkts++;
}
if (ret_mp) {
}
}
/*
* Print message in release-version driver.
*/
static void
{
} else {
}
}
/*
* To allocate & initilize all resources.
* Called by amd8111s_attach().
*/
static int
{
unsigned long *pmem_req_array;
unsigned long *pmem_set_array;
int i, size;
for (i = 0; i < MEM_REQ_MAX; i++) {
mem_req_array[i] = 0;
mem_set_array[i] = 0;
}
while (*pmem_req_array) {
switch (*pmem_req_array) {
case VIRTUAL:
*(pmem_set_array) = *(pmem_req_array);
*(pmem_set_array) = (unsigned long) kmem_zalloc(
*(pmem_req_array), KM_NOSLEEP);
if (*pmem_set_array == NULL)
goto odl_init_failure;
break;
}
}
/*
* Initilize memory on lower layers
*/
*pmem_set_array = NULL;
goto odl_init_failure;
}
/*
* Allocate Rx buffer for each Rx descriptor. Then call mil layer
* routine to fill physical address of Rx buffer into Rx descriptor.
*/
*pmem_set_array = NULL;
goto odl_init_failure;
}
return (0);
/*
* Free All memory allocated so far
*/
switch (*pmem_req_array) {
case VIRTUAL:
pmem_req_array++; /* Size */
size = *(pmem_req_array);
pmem_req_array++; /* Virtual Address */
if (pmem_req_array == NULL)
return (1);
break;
}
}
return (1);
}
/*
*/
static boolean_t
{
/*
* Allocate Rx descriptors
*/
"ddi_dma_alloc_handle for Rx desc failed");
return (B_FALSE);
}
"ddi_dma_mem_handle for Rx desc failed");
return (B_FALSE);
}
&count) != DDI_SUCCESS) {
"ddi_dma_addr_bind_handle for Rx desc failed");
return (B_FALSE);
}
/* Initialize Rx descriptors related variables */
pMil->Rx_desc_pa = (unsigned int)
/*
* Allocate Tx descriptors
*/
"ddi_dma_alloc_handle for Tx desc failed");
goto allocate_desc_fail;
}
"ddi_dma_mem_handle for Tx desc failed");
goto allocate_desc_fail;
}
&count) != DDI_SUCCESS) {
"ddi_dma_addr_bind_handle for Tx desc failed");
goto allocate_desc_fail;
}
/* Set the DMA area to all zeros */
/* Initialize Tx descriptors related variables */
/* Physical Addr of Tx_desc_original & Tx_desc */
~ALIGNMENT);
/* Setting the reserved bits in the tx descriptors */
for (i = 0; i < TX_RING_SIZE; i++) {
}
return (B_TRUE);
return (B_FALSE);
}
/*
*/
static void
{
/* Free Rx descriptors */
if (pOdl->rx_desc_dma_handle) {
}
/* Free Rx descriptors */
if (pOdl->tx_desc_dma_handle) {
}
}
/*
*/
static boolean_t
struct amd8111s_dma_ringbuf *pRing,
{
"kmem_zalloc failed");
goto failed;
}
!= DDI_SUCCESS) {
"ddi_dma_alloc_handle failed");
goto failed;
!= DDI_SUCCESS) {
"ddi_dma_mem_alloc failed");
goto failed;
"ddi_dma_mem_alloc failed");
goto failed;
"ddi_dma_addr_bind_handle failed");
goto failed;
} else {
for (msg_acc = 0;
++ msg_acc) {
msg_idx ++;
}
}
}
return (B_TRUE);
return (B_FALSE);
}
/*
*/
static void
{
int idx;
break;
}
}
}
break;
}
}
break;
}
}
}
}
}
}
/*
* Allocate all Tx buffer.
* Allocate a Rx buffer for each Rx descriptor. Then
* call mil routine to fill physical address of Rx
* buffer into Rx descriptors
*/
static boolean_t
{
/*
* Allocate rx Buffers
*/
"amd8111s_alloc_dma_ringbuf for tx failed");
goto allocate_buf_fail;
}
/*
* Allocate Tx buffers
*/
"amd8111s_alloc_dma_ringbuf for tx failed");
goto allocate_buf_fail;
}
/*
* Initilize the mil Queues
*/
return (B_TRUE);
"amd8111s_allocate_buffers failed");
return (B_FALSE);
}
/*
*/
static void
{
/* Free Tx buffers */
/* Free Rx Buffers */
}
/*
* Try to recycle all the descriptors and Tx buffers
* which are already freed by hardware.
*/
static int
{
}
count ++;
}
return (count);
}
/*
* Get packets in the Tx buffer, then copy them to the send buffer.
* Trigger hardware to send out packets.
*/
static void
{
break;
}
/* to verify if it needs to recycle the tx Buf */
if (amd8111s_recycle_tx(pLayerPointers) == 0) {
->statistics.tx_no_descriptor ++;
break;
}
/* Fill packet length */
/* Fill physical buffer address */
}
}
/* Call mdlTransmit to send the pkt out on the network */
}
/*
* Softintr entrance. try to send out packets in the Tx buffer.
* If reschedule is True, call mac_tx_update to re-enable the
* transmit
*/
static uint_t
{
}
return (DDI_INTR_CLAIMED);
}
/*
* Get a Tx buffer
*/
static struct amd8111s_msgbuf *
{
} else {
}
return (tmp);
}
static boolean_t
{
/* alloc send buffer */
return (B_FALSE);
}
/* copy packet to send buffer */
}
return (B_TRUE);
}
/*
* (GLD Entry Point) Send the message block to lower layer
*/
static mblk_t *
{
if (!pLayerPointers->run) {
}
/* Send fail */
break;
}
}
return (mp);
}
/*
* (GLD Entry Point) Interrupt Service Routine
*/
static uint_t
{
unsigned int intrCauses;
/* Read the interrupt status from mdl */
if (intrCauses == 0) {
return (DDI_INTR_UNCLAIMED);
}
if (intrCauses & LCINT) {
/* Link status changed */
}
} else {
}
}
}
/*
* RINT0: Receive Interrupt is set by the controller after the last
* descriptor of a receive frame for this ring has been updated by
* writing a 0 to the OWNership bit.
*/
if (intrCauses & RINT0) {
}
/*
* TINT0: Transmit Interrupt is set by the controller after the OWN bit
* in the last descriptor of a transmit frame in this particular ring
* has been cleared to indicate the frame has been copied to the
* transmit FIFO.
*/
if (intrCauses & TINT0) {
/*
* if desc ring is NULL and tx buf is not NULL, it should
* drain tx buffer
*/
}
if (intrCauses & STINT) {
}
return (DDI_INTR_CLAIMED);
}
/*
* To re-initilize data structures.
*/
static void
{
}
/*
* Send all pending tx packets
*/
static void
{
int i, desc_count = 0;
for (i = 0; i < 30; i++) {
/* This packet has been transmitted */
pTx_desc ++;
desc_count ++;
}
if (desc_count == TX_RING_SIZE) {
break;
}
/* Wait 1 ms */
drv_usecwait(1000);
}
}
/*
* (GLD Entry Point) To start card will be called at
* ifconfig plumb
*/
static int
{
return (0);
}
/*
* (GLD Entry Point) To stop card will be called at
* ifconfig unplumb
*/
static void
{
/* Ensure send all pending tx packets */
/*
* Stop the controller and disable the controller interrupt
*/
}
/*
* To clean up all
*/
static void
{
/* Free memory on lower layers */
while (*pmem_free_array) {
switch (*pmem_free_array) {
case VIRTUAL:
size = *(++pmem_free_array);
break;
}
}
}
/*
*
*/
static int
{
if (add) {
/* Add a multicast entry */
} else {
/* Delete a multicast entry */
}
return (0);
}
#ifdef AMD8111S_DEBUG
/*
* The size of MIB registers is only 32 bits. Dump them before one
* of them overflows.
*/
static void
{
/*
* Rx Counters
*/
/*
* Tx Counters
*/
/* Clear all MIB registers */
}
#endif
/*
*/
static int
{
if (on) {
} else {
}
return (0);
}
/*
* (Gld Entry point) Changes the Mac address of card
*/
static int
{
return (0);
}
/*
* Reset the card
*/
void
{
}
/*
* attach(9E) -- Attach a device to the system
*
* Called once for each board after successfully probed.
* will do
* a. creating minor device node for the instance.
* b. allocate & Initilize four layers (call odlInit)
* c. get MAC address
* d. initilize pLayerPointers to gld private pointer
* e. register with GLD
* if any action fails does clean up & returns DDI_FAILURE
* else retursn DDI_SUCCESS
*/
static int
{
switch (cmd) {
case DDI_ATTACH:
break;
default:
return (DDI_FAILURE);
}
pLayerPointers = (struct LayerPointers *)
/* Get device instance number */
/*
* Here, we only allocate memory for struct odl and initilize it.
* All other memory allocation & initilization will be done in odlInit
* later on this routine.
*/
!= DDI_SUCCESS) {
"attach: get iblock cookies failed");
goto attach_failure;
}
/* Setup PCI space */
return (DDI_FAILURE);
}
/*
* Allocate and initialize all resource and map device registers.
* If failed, it returns a non-zero value.
*/
if (amd8111s_odlInit(pLayerPointers) != 0) {
goto attach_failure;
}
"attach: ddi_regs_map_setup failed");
goto attach_failure;
}
/* Initialize HW */
/*
* Setup the interrupt
*/
goto attach_failure;
}
/*
* Setup soft intr
*/
goto attach_failure;
}
/*
* Initilize the mac structure
*/
goto attach_failure;
/* Get MAC address */
/* 1518 - 14 (ether header) - 4 (CRC) */
/*
* Finally, we're ready to register ourselves with the MAC layer
* interface; if this succeeds, we're ready to start.
*/
goto attach_failure;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* detach(9E) -- Detach a device from the system
*
* It is called for each device instance when the system is preparing to
* unload a dynamically unloadable driver.
* will Do
* a. check if any driver buffers are held by OS.
* b. do clean up of all allocated memory if it is not in use by OS.
* c. un register with GLD
* d. return DDI_SUCCESS on succes full free & unregister
* else GLD_FAILURE
*/
static int
{
switch (cmd) {
case DDI_DETACH:
break;
default:
return (DDI_FAILURE);
}
/*
* Get the driver private (struct LayerPointers *) structure
*/
return (DDI_FAILURE);
}
}
static int
{
/* Unregister driver from the GLD interface */
return (DDI_FAILURE);
}
}
}
}
/* Stop HW */
}
/* Free All memory allocated */
}
}
return (DDI_SUCCESS);
}
/*
* (GLD Entry Point)GLD will call this entry point perodicaly to
* get driver statistices.
*/
static int
{
switch (stat) {
/*
* Current Status
*/
case MAC_STAT_IFSPEED:
break;
case ETHER_STAT_LINK_DUPLEX:
*val = LINK_DUPLEX_FULL;
} else {
*val = LINK_DUPLEX_HALF;
}
break;
/*
* Capabilities
*/
case ETHER_STAT_CAP_1000FDX:
*val = 0;
break;
case ETHER_STAT_CAP_1000HDX:
*val = 0;
break;
case ETHER_STAT_CAP_100FDX:
*val = 1;
break;
case ETHER_STAT_CAP_100HDX:
*val = 1;
break;
case ETHER_STAT_CAP_10FDX:
*val = 1;
break;
case ETHER_STAT_CAP_10HDX:
*val = 1;
break;
case ETHER_STAT_CAP_ASMPAUSE:
*val = 1;
break;
case ETHER_STAT_CAP_PAUSE:
*val = 1;
break;
case ETHER_STAT_CAP_AUTONEG:
*val = 1;
break;
*val = 0;
break;
*val = 0;
break;
*val = 1;
break;
*val = 1;
break;
case ETHER_STAT_ADV_CAP_10FDX:
*val = 1;
break;
case ETHER_STAT_ADV_CAP_10HDX:
*val = 1;
break;
*val = 1;
break;
case ETHER_STAT_ADV_CAP_PAUSE:
*val = 1;
break;
*val = 1;
break;
/*
* Rx Counters
*/
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_NORCVBUF:
break;
case MAC_STAT_IERRORS:
break;
case ETHER_STAT_ALIGN_ERRORS:
break;
case ETHER_STAT_FCS_ERRORS:
break;
/*
* Tx Counters
*/
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_OERRORS:
break;
case MAC_STAT_COLLISIONS:
break;
break;
break;
case ETHER_STAT_EX_COLLISIONS:
break;
break;
case ETHER_STAT_DEFER_XMTS:
break;
default:
return (ENOTSUP);
}
return (0);
}
/*
* Memory Read Function Used by MDL to set card registers.
*/
unsigned char
{
}
int
{
(uint16_t *)(x)));
}
long
{
(uint32_t *)(x)));
}
void
{
}
void
{
}
void
{
}
void
{
int i;
for (i = 0; i < 8; i++) {
WRITE_REG8(pLayerPointers, (x + i), y[i]);
}
}