* no. of the DP83840 chip. For Rev-C of DP83840, the rev. no. is 0. * The next revision of the chip is called DP83840A and the value of * HME_NSIDR2 is 0x5c01 for this new chip. All the workarounds specific * to DP83840 chip are valid for both the revisions of the chip. * Assuming that these workarounds are valid for the future revisions * also, we will apply these workarounds independent of the revision no. * Hence we mask out the last 4 bits of the IDR2 register and compare * Likewise for the QSI 6612 Fast ethernet phy. * Addition Interface Technologies Group (NPG) 8/28/1997. * All strings used by hme messaging functions "No response from Ethernet network : Link down -- cable problem?";
"Driver is BUSY with upper layer";
"Parallel detection fault.";
"Transceiver does not talk MII.";
"Transceiver isolate failed.";
"Internal Transceiver Selected.";
"External Transceiver Selected.";
"Dev not used - dev in slave only slot";
"Could not identify the burst size";
"Unknown receive RINGSZ";
"Using local MAC address";
"Local Ethernet address = %s";
"ddi_add_intr(9F) failed";
"ddi_create_minor_node(9F) failed";
"ddi_regs_map_setup(9F) for global reg failed";
"ddi_map_regs for etx reg failed";
"ddi_map_regs for erx reg failed";
"ddi_map_regs for bmac reg failed";
"ddi_map_regs for mif reg failed";
"parameter register error";
"ddi_dev_nregs failed(9F), returned %d";
"Invalid number of registers.";
"External Transceiver: anar not set with speed selection";
"External Transceiver: anar not set with speed selection";
"ddi_regs_map_setup(9F) for config space failed";
"Attach entry point failed";
"Attach entry point rcv'd a bad command";
"Detach entry point rcv'd a bad command";
"Unknown Rx descriptor size %x.";
"Txmac could not be disabled.";
"Rxmac could not be disabled.";
"Configuration space failed in routine.";
"ddi_regs_map_setup(9F) for soft reset failed";
"Unknown Tx descriptor size %x.";
"Can not allocate Tx dma handle.";
"Can not allocate Rx dma handle.";
"The current Phy/xcvr speed is not valid";
"Parallel Detection Fault";
"Autonegotiated speed is bad";
* "MIF Read failure: data = %X"; * SunVTS Loopback messaging support * static char *loopback_val_default = * "Loopback Value: Error In Value."; * static char *loopback_cmd_default = * "Loopback Command: Error In Value."; #
define ND_BASE (
'N' <<
8)
/* base */ * Module linkage structures. nodev,
/* int (*cb_aread)() */ nodev /* int (*cb_awrite)() */ * Claim the device is ultra-capable of burst in the beginning. Use * the value returned by ddi_dma_burstsizes() to actually set the HME * global configuration register later. * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains * the the burstsizes in both the lo and hi words. (
uint64_t)
0x00ffffff,
/* address counter max */ (
uint_t)
0x00700070,
/* dlim_burstsizes for 32 and 64 bit xfers */ (
uint32_t)
0x1,
/* minimum transfer size */ (
uint64_t)
0x7fffffff,
/* maximum transfer size */ (
uint64_t)
0x00ffffff,
/* maximum segment size */ (
uint_t)
0x00700070,
/* dlim_burstsizes for 32 and 64 bit xfers */ * This is the loadable module wrapper. * Module linkage information for the kernel. "10/100Mb Ethernet Driver v%I%",
* Autoconfiguration lock: We want to initialize all the global * locks at _init(). However, we do not have the cookie required which * is returned in ddi_add_intr(), which in turn is usually called at attach * Linked list of active (inuse) driver Streams. * Single private "global" lock for the few rare conditions * we want single-threaded. #
define HME_BB1 0x15 /* Babybac1, Rev 1.5 */#
define HME_BB2 0x20 /* Babybac2, Rev 0 *//* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */ * Ether_copy is not endian-correct. Define an endian-correct version. * Ether-type is specifically big-endian, but data region is unknown endian /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */ * The following code is used for performance metering and debugging; * This routine is invoked via "TIME_POINT(label)" macros, which will * store the label and a timestamp. This allows to execution sequences * and timestamps associated with them. /* time_point_active = 0; disable at end */ * Calculate the bit in the multicast address filter that selects the given * Just want the 6 most significant bits. /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ * To read the MII register bits from the Babybac1 transceiver * To read the MII register bits according to the IEEE Standard for (i =
4; i >= 0; i--) {
/* <AAAAA> */ for (i =
4; i >= 0; i--) {
/* <RRRRR> */ for (i =
0xf; i >= 0; i--) {
/* <DDDDDDDDDDDDDDDD> */ /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ for (i =
4; i >= 0; i--) {
/* <AAAAA> */ for (i =
4; i >= 0; i--) {
/* <RRRRR> */ for (i =
0xf; i >= 0; i--) {
/* <DDDDDDDDDDDDDDDD> */ * Kludge to get the Transceiver out of hung mode for (i =
0xf; i >= 0; i--) {
/* <DDDDDDDDDDDDDDDD> */ * Kludge to get the Transceiver out of hung mode for (i = 0; i <
33; i++) {
/* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ return (
1);
/* No transceiver present */ "Frame Register used for MII");
"Frame Reg :mii_read: phyad = %X reg = %X ",
phyad,
regad);
* HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); "Frame Reg :mii_read: successful:data = %X ", *
datap);
"FRame Reg :mii_write: phyad = %X \ * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); "Frame Reg :mii_write: successful");
* hme_stop_timer function is used by a function before doing link-related * processing. It locks the "hme_linklock" to protect the link-related data * structures. This lock will be subsequently released in hme_start_timer(). * hme_select_speed is required only when auto-negotiation is not supported. * It should be used only for the Internal Transceiver and not the External * transceiver because we wouldn't know how to generate Link Down state on * Currently it is required to support Electron 1.1 Build machines. When all * these machines are upgraded to 1.2 or better, remove this function. * Returns 1 if the link is up, 0 otherwise. "Default in select speed 100");
"Default in select speed 10");
"Default in select speed : Neither speed");
/* insure a good reset of the QSI PHY */ /* Isolate the Internal Transceiver */ /* select the External transceiver */ /* Isolate the External transceiver, if present */ /* select the Internal transceiver */ * Now reset the transceiver. * Check for transceiver reset completion. "reset_trans: reset complete.");
* Get the PHY id registers. We need this to implement work-arounds * for bugs in transceivers which use the National DP83840 PHY chip. * National should fix this in the next release. "reset_trans: control = %x status = %x idr1 = %x idr2 = %x anar = %x",
* The strapping of AN0 and AN1 pins on DP83840 cannot select * 10FDX, 100FDX and Auto-negotiation. So select it here for the * Modify control and bmsr based on anar for Rev-C of DP83840. if (n ==
1) {
/* only one mode. disable auto-negotiation */ "DP83840 Rev-C found: Modified bmsr = %x " * Place the Transceiver in normal operation mode * check if the transceiver is not in Isolate mode "reset_trans: isolate complete.");
* Work-around for the late-collision problem with 100m cables. * National should fix this in the next release ! "hme_reset_trans: CSC read = %x written = %x",
* If the MIF Polling is ON, and Internal transceiver is in use, just * check for the presence of the External Transceiver. * First check to see what transceivers are out there. * If an external transceiver is present * then use it, regardless of whether there is a Internal transceiver. * If Internal transceiver is present and no external transceiver * then use the Internal transceiver. * If there is no external transceiver and no Internal transceiver, * then something is wrong so print an error message. "check_trans: polling_on: cfg = %X",
cfgsav);
"Extern Transcvr Disconnected");
"check_trans: polling_off: cfg = %X",
cfgsav);
"hme_link_control: force 100T4 hdx");
/* 100fdx needs to be checked first for 100BaseFX */ "hme_link_control: force 100 hdx");
/* 10hdx needs to be checked first for MII-AUI */ /* MII-AUI BugIds 1252776,4032280,4035106,4028558 */ "hme_link_control: force 10 hdx");
/* Decide if transmitter went dead and reinitialize everything */ /* Something needs to be sent out but it is not going out */ * Called as a result of HME_LINKCHECK_TIMER timeout, to poll for Transceiver * change or when a transceiver change has been detected by the hme_try_speed * This function will also be called from the interrupt handler when polled mode * is used. Before calling this function the interrupt lock should be freed * so that the hmeinit() may be called. * Note that the hmeinit() function calls hme_select_speed() to set the link * speed and check for link status. * This condition was added to work around for * Basically if the link is up but no packets * are being received. This can be checked using * ipackets, which in case of reception will * continue to increment after 'hmep->hme_iipackets' * has been made equal to it and the 'hme_check_link' * timer has expired. Note this could also be done * if there's no traffic on the net. * 'hmep->hme_ipackets' is incremented in hme_read * for successfully received packets. * Receptions are occurring set 'hmep->hme_iipackets' * to 'hmep->hme_ipackets' to monitor if receptions * occur during the next timeout interval. * Receptions not occurring could be due to * Synoptics problem, try switchin of data * scrabbling. That should bring up the link. (
void)
hmeinit(
hmep);
/* To reset the transceiver and */ /* to init the interface */ * check if the transceiver is the same. * init to be done if the external transceiver is (
void)
hmeinit(
hmep);
/* To reset the transceiver and */ /* to init the interface */ "int_flag = %X old_stat = %X stat = %X",
"hme_check_link:DOWN polled data = %X\n",
stat);
"hme_check_link:after poll-stop: stat = %X",
/* Transceiver does not talk mii */ "mifpoll_flag = %x first stat = %X",
"second stat = %X",
stat);
* The PHY may have automatically renegotiated link speed and mode. * Get the new link speed and mode. /* Reset the PHY and bring up the link */ * Disable link pulses for the Internal Transceiver "hme_disable_link_pulse: NICR read = %x written = %x",
"hme_force_speed entered");
* To interoperate with auto-negotiable capable systems * the link should be brought down for 1 second. * How to do this using only standard registers ? "hme_force_speed: begin:control =" " %X stat = %X aner = %X anar = %X" "hme_force_speed:end: control =" "%X stat = %X aner = %X anar = %X anlpar = %X",
"hme_try_autoneg: Link Partner AN able");
"hme_try_autoneg: anar not set with speed selection");
" hme_try_autoneg: parallel detection done");
" hme_try_autoneg: parallel detection: anar not set with speed selection");
* Return 1 if the link is up or auto-negotiation being tried, 0 otherwise. /* auto negotiation not initiated */ * Transceiver does not talk mii " PHY status reg = %X",
stat);
" Auto-negotiation not supported");
* Read ANER to clear status from previous operations. * Transceiver does not talk mii * auto-negotiation initiated * auto-negotiation in progress * Auto-negotiation has been in progress. Wait for at least * Changed 8/28/97 to fix bug ID 4070989. * Transceiver does not talk mii * wait for a maximum of 5 seconds "Auto-negotiation not completed in 5 seconds");
" PHY status reg = %X",
stat);
" PHY anar reg = %x",
anar);
" PHY aner reg = %x",
aner);
" PHY anlpar reg = %x",
anlpar);
" hme_try_autoneg: MLF Detected" "Auto-negotiation completed within %d 100ms time",
hmep->
hme_delay);
* wait for a maximum of 10 seconds "Link not Up in 10 seconds: stat = %X",
stat);
"Retry Auto-negotiation.");
* This function is used to perform automatic speed detection. * The Internal Transceiver which is based on the National PHY chip * 83840 supports auto-negotiation functionality. * Some External transceivers may not support auto-negotiation. * In that case, the software performs the speed detection. * The software tries to bring down the link for about 2 seconds to * force the Link Partner to notice speed change. * The software speed detection favors the 100 Mbps speed. * It does this by setting the 100 Mbps for longer duration ( 5 seconds ) * than the 10 Mbps ( 2 seconds ). Also, even after the link is up * in 10 Mbps once, the 100 Mbps is also tried. Only if the link * is not up in 100 Mbps, the 10 Mbps speed is tried again. return;
/* auto negotiation successful or being tried */ * Work-around for the scramble problem with QSI * chip and Synoptics 28115 switch. * Addition Interface Technologies Group (NPG) 8/28/1997. * Addition of a check for 'hmep->hme_forcespeed' * This is necessary when the autonegotiation is * disabled by the 'hme.conf' file. In this case * hmep->hme_tryspeed is not initialized. Resulting * in the workaround not being applied. /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */ * Allocate and zero-out "number" structures * each of type "structure" in kernel memory. * Translate a kernel virtual address to i/o address. * ddi_dma_sync() a TMD or RMD descriptor. * Ethernet broadcast address definition. 0xff,
0xff,
0xff,
0xff,
0xff,
0xff * Linked list of hme structures - one per card. * force the fallback to ddi_dma routines * Our DL_INFO_ACK template. 0,
/* dl_current_state */ * Get properties from old VPD /* Get local-mac-address */ "hme_get_oldvpd model: ddi_prop_create error");
* Get properties from new VPD maxvpdsize =
1024;
/* Real size not known until after it is read */ break;
/* no VPD found */ /* Get all keywords in this VPD */ * Get properties from VPD if ((
v0 &
0xffff) !=
0x55aa) {
&
0xff) ==
0x50)
/* 'P' */ &
0xff) ==
0x43)
/* 'C' */ &
0xff) ==
0x49)
/* 'I' */ &
0xff) ==
0x52) {
/* 'R' */ break;
/* VPD pointer found */ return (
1);
/* unknown start byte in VPD */ * map configuration space "ddi_map_regs for config space failed");
* Enable bus-master and memory accesses "reg mapping failed: Check reg property ");
return (0);
/* SUCCESS */ "SBus 2.1 Found (Rev Id = %x)",
hm_rev);
"SBus 2.0 Found (Rev Id = %x)",
hm_rev);
"PCI IO 1.0 Found (Rev Id = %x)",
"%s (Rev Id = %x) Found",
* Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready /* Do hmeinit() only for active interface */ * Allocate soft device data structure * Might as well set up elements of data structure * Might as well setup the driver private * structure as part of the dip. * Reject this device if it's in a slave-only slot. * Map in the device registers. * Reg # 0 is the Global register set * Reg # 1 is the ETX register set * Reg # 2 is the ERX register set * Reg # 3 is the BigMAC register set. * Reg # 4 is the MIF register set case 3:
/* for hot swap/plug, there will be 3 entries in "reg" prop */ /* Initialize device attributes structure */ * Map the PCI config space "pci_config_setup() failed..");
* Get parent pci bridge info. * "set hme:pci_latency_timer=0xYY" * Ensure minimum cheerio latency timer of 0x50 * Usually OBP or pci bridge should set this value * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8 * Some system set cheerio LT at 0x40 * Now program cheerio's pci latency timer with newLT }
else {
/* Map register sets */ }
/* Endif cheerio_mode */ * Based on the hm-rev, set some capabilities * Set up default capabilities for HM 2.0 /* NEW routine to get the properties */ * hm_rev property not found so, this is * case of hot insertion of card without interpreting fcode. * Get it from revid in config space after mapping it. "hmeattach: ddi_map_regs for config space failed");
* Since this is cheerio-based PCI card, we write 0xC in the * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1) "hmeattach: ddi_prop_create error for hm_rev");
"hmeattach: no promprops");
" high-level interrupts are not supported");
* Get intr. block cookie so that mutex locks can be initialized. * Initialize mutex's for this device. * Add interrupt to system * Set up the ethernet mac address. * Create the filesystem device node. /* lock hme structure while manipulating link list of hme structs */ * hmewenlock and hmestruplock are destroy-ed in _fini() "hmeattach: Unsuccessful Exiting");
* This bug manifests by allowing the driver to allow detach * while the driver is busy and subsequent packets cause * Make driver quiescent, we don't want to prevent the * Remove instance of the intr * Destroy all mutexes and data structures allocated during * Remove hmep from the link list of device structures "dma_unbind_handle failed");
* Generated when there was only dma. * else HME_FAULT_MSG1(NULL, SEVERITY_HIGH, * Reset hme_device to default value(-1) when ndd is * referencing the instance being detached. "==> hmeinit_xfer_params");
* Set up the start-up values for user-configurable parameters * Get the values from the global variables first. * Use the MASK to limit the value to allowed maximum. * The link speed may be forced to either 10 Mbps or 100 Mbps using the * property "transfer-speed". This may be done in OBP by using the * command "apply transfer-speed=<speed> <device>". The speed may be "params: transfer-speed property = %X", i);
* Get the parameter values configured in .conf file. "params: link-pulse-disable property found.");
* Return 0 upon success, 1 on failure. * Disable the Tx dma engine. * Disable the Rx dma engine. * By this time all things should be quiet, so hit the "cannot stop hme - failed to access device");
* Update all the stats by reading all the counter registers. * Counter register stats are not updated till they overflow * PSARC 1997/198 : 64 bit kstats * PSARC 1997/247 : RFC 1643 * RFE's (Request for Enhancement) * hmep->hme_pci_speed = hkp->hk_pci_peed.value.ul; * PSARC 1997/247 : RFC 1643 * RFE's (Request for Enhancements) * hkp->hk_pci_speed.value.ul = hmep->pci_speed; * PSARC 1997/247 : RFC 1643 * kstat_named_init(&hkp->hk_pci_speed, "pci_bus_speed", * kstat_named_init(&hkp->hk_pci_size, "pci_bus_width", * Assorted DLPI V2 routines. * Serialize all driver open and closes. * Determine minor device number. "hmeopen: sbp = %X\n",
sbp);
* Link new entry into the list of active entries. * Disable automatic enabling of our write service procedure. * We control this explicitly. /* inform framework we are a good citizen */ * Implicit detach Stream from interface. * Unlink the per-Stream entry from the active list and free it. "hmewput start: wq %p",
wq);
* If any msgs already enqueued or the interface will * loop back up the message (due to HMEPROMISC), then * enqueue the msg. Otherwise just xmit it directly. * Break the association between the current thread and * the thread that calls hmeproto() to resolve the * problem of hmeintr() threads which loop back around * to call hmeproto and try to recursively acquire "Default in message type");
* internal locks that are held across upstream putnext calls. * Specifically there's the problem of hmeintr() holding hme_intrlock * and hmestruplock when it calls putnext() and that thread looping * back around to call hmewput and, eventually, hmeinit() to create a * recursive lock panic. There are two obvious ways of solving this * problem: (1) have hmeintr() do putq instead of putnext which provides * the loopback "cutout" right at the rq, or (2) allow hmeintr() to putnext * and put the loopback "cutout" around hmeproto(). We choose the latter * for performance reasons. * M_DATA messages are enqueued on the wq *only* when the xmit side * is out of tbufs or tmds. Once the xmit resource is available again, * wsrv() is enabled and tries to xmit all the messages on the wq. "hmeproto start: wq %p dlprim %X",
wq,
prim);
"hmeproto end: wq %p dlprim %X",
wq,
prim);
if (
hme_device == -
1) {
/* select the first one found */ if (
hmep ==
NULL) {
/* no device present */ "hmeioctl:false ret from hme_nd_getset");
"hmeioctl:true ret from hme_nd_getset");
if (
hmep ==
NULL) {
/* no device present */ "HME_IOC default get speed");
/* Enable display of linkup message */ "HME_IOC default set speed");
"HMEIOC default nor s/get speed");
"HME_IOC default command");
* M_DATA "fastpath" info request. * Following the M_IOCTL mblk should come a DL_UNITDATA_REQ mblk. * We ack with an M_IOCACK pointing to the original DL_UNITDATA_REQ mblk * followed by an mblk containing the raw ethernet header corresponding * to the destination address. Subsequently, we may receive M_DATA * msgs which start with this header and may send up * up M_DATA msgs with b_rptr pointing to a (ulong_t) group address * indicator followed by the network-layer data (IP packet header). * This is all selectable on a per-Stream basis. * Sanity check the DL_UNITDATA_REQ destination address * offset and length values. * Allocate a new mblk to hold the ether header. * Fill in the ether header. * Link new mblk in after the "request" mblks. /* Set link to device and update our state. */ * Has device been initialized? Do so if necessary. * Also check if promiscuous mode is set via the ALLPHYS and * ALLMULTI flags, for the stream. If so, initialize the * Initialize the Interrupt mask * The init will clear upon entry * and reset upon success. * Detach a Stream from an interface. /* Disable promiscuous mode if on. */ /* Disable ALLSAP mode if on. */ /* Disable ALLMULTI mode if on. */ /* Disable any Multicast Addresses. */ * Detach from device structure. * when no other streams are attached to it. * Save SAP value for this Stream and change state. /* Exchange current msg for a DL_INFO_ACK. */ /* Fill in the DL_INFO_ACK fields and reply. */ * This is to support unlimited number of members * Calculate hash value and bucket. * Allocate hash bucket if it's not there. * We no longer bother checking to see if the address is already * in the table (bugid 1209733). We won't reinitialize the * hardware, since we'll find the mc bit is already set. * Expand table if necessary. * Add address to the table. * If this address's bit was not already set in the local address * filter, add it and re-initialize the Hardware. * Calculate hash value, get pointer to hash bucket for this address. * Try and delete the address if we can find it. * If there's more than one address in this * bucket, delete the unwanted one by moving * the last one in the list over top of it; * otherwise, just free the bucket. * If this address's bit should no longer be * set in the local address filter, clear it and * re-initialize the Hardware * Error if length of address isn't right or the address * specified is a multicast or broadcast address. * Error if this stream is not attached to a device. * Set new interface local address and re-init device. * This is destructive to any other streams attached * Validate destination address format. * Error if no M_DATA follows. * Create ethernet header by either prepending it onto the * next mblk if possible, or reusing the M_PROTO block if not. * Space available for ethernet hdr in M_DATA payload * Space available in dl_unitdata_req M_PROTO blk. Reuse it. * M_PROTO and M_DATA did not have space for ethernet hdr. * In 802.3 mode, the driver looks at the * sap field of the DL_BIND_REQ being 0 in addition to the destination * sap field in the range [0-1500]. If either is true, then the driver * computes the length of the message, not including initial M_PROTO * mblk (message block), of all subsequent DL_UNITDATA_REQ messages and * transmits 802.3 frames that have this value in the MAC frame header * Report interface speed in Kb/Sec * Notify streams that are attached to *this* instance only. * Report interface speed in Kb/Sec. * here we deal with 3 cases. * 1. pkt has exactly one mblk * 2. pkt has exactly two mblks * 3. pkt has more than 2 mblks. Since this almost * always never happens, we copy all of them * into a msh with one mblk. * for each mblk in the message, we allocate a tmd and * figure out the tmd index. The index is then used to bind * a DMA handle to the mblk and set up an IO mapping.. "hmestart: 1 buf: len = %ld b_rptr = %p",
"hmestart: 2 buf: len = %ld b_rptr = %p, " "hmestart: > 1 buf: len = %ld b_rptr = %p",
"ddi_dma_alloc_handle failed");
"ddi_dma_addr_bind_handle failed");
/* apparently they don't handle multiple cookies */ "dmaxh crossed page boundary - failed");
"ddi_dma_alloc_handle failed");
"ddi_dma_addr_bind_handle failed");
/* apparently they don't handle multiple cookies */ "dmaxh crossed page boundary - failed");
* Return zero on success, * otherwise put msg on wq, set 'want' flag and return nonzero. * update MIB II statistics * reclaim if there are more than HMETPENDING descriptors * here we deal with 3 cases. * 1. pkt has exactly one mblk * 2. pkt has exactly two mblks * 3. pkt has more than 2 mblks. Since this almost * always never happens, we copy all of them * into a msh with one mblk. * for each mblk in the message, we allocate a tmd and * figure out the tmd index. This index also passed to * dvma_kaddr_load(), which establishes the IO mapping * for the mblk data. This index is used as a index into * the ptes reserved by dvma_reserve * Check with HW: The minimum len restriction different "hmestart: Transmitted a frame");
* Return 0 on success, nonzero on error. * The recommended sequence for initialization is: * 1. Issue a Global Reset command to the Ethernet Channel. * 2. Poll the Global_Reset bits until the execution of the reset has been * 2(a). Use the MIF Frame/Output register to reset the transceiver. * Poll Register 0 to till the Resetbit is 0. * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, * 100Mbps and Non-Isolated mode. The main point here is to bring the * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk * to the MII interface so that the Bigmac core can correctly reset * 2(c). Issue another Global Reset command to the Ethernet Channel and poll * the Global_Reset bits till completion. * 3. Set up all the data structures in the host memory. * 6. Program the Transmit Descriptor Ring Base Address in the ETX. * 7. Program the Receive Descriptor Ring Base Address in the ERX. * 8. Program the Global Configuration and the Global Interrupt Mask Registers. * 9. Program the ETX Configuration register (enable the Transmit DMA channel). * 10. Program the ERX Configuration register (enable the Receive DMA channel). * 11. Program the XIF Configuration Register (enable the XIF). * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). int alloc_ret;
/* hmeallocthings() return value */ "hmeinit start: hmep %p #0805",
hmep);
* This should prevent us from clearing any interrupts that may occur by * temporarily stopping interrupts from occurring for a short time. * We need to update the interrupt mask later in this function. * hme_intrlock, hmestruplock and hme_xmitlock. * Rearranged the mutex acquisition order to solve the deadlock * situation as described in bug ID 4065896. * Initializing 'hmep->hme_iipackets' to match current * number of received packets. * Perform Global reset of the Sbus/FEPS ENET channel. * Allocate data structures. * Hang out receive buffers. "ddi_dma_alloc_handle of bufs failed");
"ddi_dma_addr_bind_handle of bufs failed");
/* apparently they don't handle multiple cookies */ "dmarh crossed page boundary - failed");
* Reset RMD and TMD 'walking' pointers. * Determine if promiscuous mode. * This is the right place to initialize MIF !!! * Depending on the transceiver detected, select the source * of the clocks for the MAC. Without the clocks, TX_MAC does * not reset. When the Global Reset is issued to the Sbus/FEPS * ASIC, it selects Internal by default. /* Isolate the Int. xcvr */ * Perform transceiver reset and speed selection only if * Reset the PHY and bring up the link * If it fails we will then increment a kstat. * Initialize BigMAC registers. * First set the tx enable bit in tx config reg to 0 and poll on * it till it turns to 0. Same for rx config, hash and address * Here is the sequence per the spec. * HASH3, HASH2, HASH1, HASH0 for group address * AFR2, AFR1, AFR0 and AFMR for address filter mask * Program RXMIN and RXMAX for packet length if not 802.3 * RXCFG - Rx config for not stripping CRC * XXX Anything else to hme configured in RXCFG * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN * XIF register for speed selection * Initialize the TX_MAC registers * Initialization of jamsize to work around rx crc bug /* Initialize the RX_MAC registers */ * Program BigMAC with local individual ethernet address. * Set up multicast address filter by passing all multicast * addresses through a crc generator, and then using the * low order 6 bits as a index into the 64 bit logical * address filter. The high order three bits select the word, * while the rest of the bits select the bit within the word. * Here we initialize the MC Hash bits for (i = 0; i <
4; i++) {
break;
/* All bits are already on */ * Set up the address filter now? * Initialize HME Global registers, ETX registers and ERX registers. * ERX registers can be written only if they have even no. of bits set. * So, if the value written is not read back, set the lsb and write * static int hme_erx_fix = 1; : Use the fix for erx bug * Significant performance improvements can be achieved by * disabling transmit interrupt. Thus TMD's are reclaimed only * when we run out of them in hmestart(). /* get the rxring size bits */ * Bug related to the parity handling in ERX. When erxp-config is * Sbus/FEPS drives the parity bit. This value is used while * This fixes the RECV problem in SS5. * static int hme_erx_fix = 1; : Use the fix for erx bug "error:temp = %x erxp->config = %x, should be %x",
* Set up the rxconfig, txconfig and seed register without enabling * them the former two at this time * BigMAC strips the CRC bytes by default. Since this is * contrary to other pieces of hardware, this bit needs to * enabled to tell BigMAC not to strip the CRC bytes. * Do not filter this node's own packets. * Update the interrupt mask : this will re-allow interrupts to occur * Release the locks in reverse order * Calculate the dvma burstsize by setting up a dvma temporarily. Return * 0 as burstsize upon failure as it signifies no burst size. * Requests for 64-bit transfer setup, if the platform supports it. * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f), * sun4u Ultra-2 incorrectly returns a 32bit transfer. * Use user-configurable parameter for enabling 64-bit transfers * Free and dvma_unload pending xmit and recv buffers. * Maintaining the 1-to-1 ordered sequence of * Always unload anything before loading it again. * Never unload anything twice. Always unload * before freeing the buffer. We satisfy these * requirements by unloading only those descriptors * which currently have an mblk associated with them. * Keep the ddi_dma_free() before the freeb() * Race condition with snoop. * This was generated when only a dma handle is expected. * else HME_FAULT_MSG1(NULL, SEVERITY_HIGH, FREE_MSG, * "hme: Expected a dma read handle:failed"); * hme_start_mifpoll() - Enables the polling of the BMSR register of the PHY. * After enabling the poll, delay for atleast 62us for one poll to be done. * Then read the MIF status register to auto-clear the MIF status field. * Then program the MIF interrupt mask register to enable interrupts for the * LINK_STATUS and JABBER_DETECT bits. /* Do not poll for Jabber Detect for 100 Mbps speed */ "mifpoll started: mif_cfg = %X mif_bsts = %X",
* Un-initialize (STOP) HME channel. * Allow up to 'HMEDRAINTIME' for pending xmit's to complete. * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and * map it in IO space. Allocate space for transmit and receive ddi_dma_handle * structures to use the DMA interface. * Return if resources are already allocated. * Allocate the TMD and RMD descriptors and extra for page alignment. "cannot allocate rmd handle - failed");
"cannot allocate trmd dma mem - failed");
"cannot allocate trmd dma - failed");
"trmds crossed page boundary - failed");
* dvma_reserve() reserves DVMA space for private man * Specifically we reserve n (HME_TMDMAX + HME_RMDMAX) * pagetable entries. Therefore we have 2 ptes for each * descriptor. Since the ethernet buffers are 1518 bytes * so they can at most use 2 ptes. * Will do a ddi_dma_addr_setup for each bufer * We will now do a dma, due to the fact that * Reserve dvma space for the receive side. If * this call fails, we have to release the resources * and fall back to the dma case. * Keep handy limit values for RMD, TMD, and Buffers. * Zero out xmit and rcv holders. * First check to see if it our device interrupting. * The status register auto-clears on read except for * Note: TINT is sometimes enabled in thr hmereclaim() * Bugid 1227832 - to handle spurious interrupts on fusion systems. * Claim the first interrupt after initialization /* No interesting interrupt */ "hmeintr: hme not running");
"hmeintr: fatal error:hmesbits = %X",
hmesbits);
"hmeintr: non-fatal error:hmesbits = %X",
hmesbits);
"hmeintr: mif interrupt: Link Down");
* BugId 1261889 EscId 50699 ftp hangs @ 10 Mbps * Here could be one cause: * national PHY sees jabber, goes into "Jabber function", * (see section 3.7.6 in PHY specs.), disables transmitter, * and waits for internal transmit enable to be de-asserted * for at least 750ms (the "unjab" time). Also, the PHY * has asserted COL, the collision detect signal. * In the meantime, the Sbus/FEPS, in never-give-up mode, * continually retries, backs off 16 times as per spec, * and restarts the transmission, so TX_EN is never * deasserted long enough, in particular TX_EN is turned * on approximately once every 4 microseconds on the * average. PHY and MAC are deadlocked. * Here is part of the fix: * On seeing the jabber, treat it like a hme_fatal_err * and reset both the Sbus/FEPS and the PHY. /* national phy only defines this at 10 Mbps */ "hmeintr: mif interrupt: Jabber detected");
/* treat jabber like a fatal error */ "jabber: re-init PHY & MAC");
"hmeintr: packet transmitted");
* This dummy PIO is required to flush the SBus "hmeintr: packet received: rmdp = %X",
rmdp);
* Sync RMD before looking at it. * Sync the next RMD before looking at it. * Transmit completion reclaiming. * Sync TMDs before looking at them. * count a chained packet only once. "reclaim: tmdp = %X index = %d",
tmdp, i);
"reclaim:ddi_dma_unbind_handle failure");
"reclaim: expected dmaxh");
* we could reclaim some TMDs so turn off interrupts * enable TINTS: so that even if there is no further activity * hmereclaim will get called * Assume mp->b_rptr points to ether_header. * While holding a reader lock on the linked list of streams structures, * attempt to match the address criteria for each stream * and pass up the raw M_DATA ("fastpath") or a DL_UNITDATA_IND. * Loop on matching open streams until (*acceptfunc)() returns NULL. * Test upstream destination sap and address match. * Test upstream destination sap and address match for HMESALLPHYS only. * Set or clear the device ipq pointer. * Assumes IPv4 and IPv6 are HMESFAST. * Prefix msg with a DL_UNITDATA_IND mblk and return the new msg. * Allocate an M_PROTO mblk for the DL_UNITDATA_IND. * Construct a DL_UNITDATA_IND primitive. * Link the M_PROTO and M_DATA together. * Return TRUE if the given multicast address is one * of those that this particular Stream is interested in. * Return FALSE if not a multicast address. * Check if all multicasts have been enabled for this Stream * Compute the hash value for the address and * grab the bucket and the number of entries in the * Return FALSE if no multicast addresses enabled for this Stream. * Otherwise, find it in the table. * Handle interrupts for fatal errors * Need reinitialization of the ENET channel. "sbus slave parity error");
"chained packet descriptor error");
* Handle interrupts regarding non-fatal errors. "first collision counter expired");
"first collision counter expired");
* This error is fatal and the board needs to * be reinitialized. Comments? "code violation counter expired");
"length error counter expired");
* and check for overflow packet also. The processing is the * same for both the cases - reuse the buffer. Update the Buffer * Sync the received buffer before looking at it. "read: ddi_dma_sync failure");
* copy the packet data and then recycle the descriptor. /* Add the First Byte offset to the b_rptr and copy */ * update MIB II statistics /* Strip the PADs for 802.3 */ * HMERMD_OWN has been cleared by the Happymeal hardware. * check for overflow packet also. The processing is the * same for both the cases - reuse the buffer. Update the Buffer * Copy small incoming packets to reduce memory consumption. The * performance loss is compensated by the reduced overhead for * DMA setup. The extra bytes before the actual data are copied * to maintain the alignment of the payload. * Add the First Byte offset to the b_rptr * update MIB II statistics * Strip the PADs for 802.3 * Start xmit on any msgs previously enqueued on any write queues. * Order of wantw accesses is important. "%s%d : %s, SEVERITY_HIGH, %s\n",
* if this is the first init do not bother to save the * counters. They should be 0, but do not count on it. /* XXX What all gets added in ierrors and oerrors? */ * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier * ndd support functions to get/set parameters /* Free the Named Dispatch Table by calling hme_nd_free */ * Extracts the value from the hme parameter array and prints the * parameter value. cp points to the required parameter. * Register each element of the parameter array with the * named dispatch handler. Each element is loaded using /* First 4 elements are read-only */ for (i = 0; i <
4; i++,
hmepa++)
/* Next 10 elements are read and write */ for (i = 0; i <
10; i++,
hmepa++)
/* next 12 elements are read-only */ for (i = 0; i <
12; i++,
hmepa++)
/* Next 3 elements are read and write */ for (i = 0; i <
3; i++,
hmepa++)
* Sets the hme parameter to the value in the hme_param_register using /* Free the table pointed to by 'ndp' */ * NOTE - logic throughout nd_xxx assumes single data block for ioctl. * However, existing code sends in some big buffers. * (temporary) hack: "*valp" is size of user buffer for copyout. If result * of action routine is too big, free excess and return ioc_rval as buffer * size needed. Return as many mblocks as will fit, free the rest. For * backward compatibility, assume size of original ioctl buffer if "*valp" /* We overwrite the name/value with the reply data */ * Load 'name' into the named dispatch table pointed to by 'ndp'. * 'ndp' should be the address of a char pointer cell. If the table * does not exist (*ndp == 0), a new table is allocated and 'ndp' * is stuffed. If there is not enough space in the table for a new * entry, more space is allocated. * Convert Ethernet address to printable (loggable) representation. static char digits[] =
"0123456789abcdef";
for (i = 0; i <
6; i++) {
* To set up the mac address for the network interface: * The adapter card may support a local mac address which is published * in a device node property "local-mac-address". This mac address is * treated as the factory-installed mac address for DLPI interface. * If the adapter firmware has used the device for diskless boot * operation it publishes a property called "mac-address" for use by * inetboot and the device driver. * If "mac-address" is not found, the system options property * "local-mac-address" is used to select the mac-address. If this option * is set to "true", and "local-mac-address" has been found, then * local-mac-address is used; otherwise the system mac address is used * by calling the "localetheraddr()" function. * Check if it is an adapter with its own local mac address * If it is present, save it as the "factory-address" * Check if the adapter has published "mac-address" property. * If it is present, use it as the mac address for this device. * Get the system ethernet address.