c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * CDDL HEADER START
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * The contents of this file are subject to the terms of the
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * Common Development and Distribution License (the "License").
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * You may not use this file except in compliance with the License.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * See the License for the specific language governing permissions
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and limitations under the License.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * When distributing Covered Code, include this CDDL HEADER in each
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * If applicable, add the following below this CDDL HEADER, with the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * fields enclosed by brackets "[]" replaced with your own identifying
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * information: Portions Copyright [yyyy] [name of copyright owner]
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * CDDL HEADER END
5ca61e50c68a7a60dc35cd76831471faa4974d71Li-Zhen You * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Use is subject to license terms.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This is the string displayed by modinfo, etc.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Make sure you keep the version ID up to date!
193974072f41a843678abf5f61979c748687e66bSherry Moorestatic char rge_ident[] = "Realtek 1Gb Ethernet";
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Used for buffers allocated by ddi_dma_mem_alloc()
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs 0, /* dma_attr_flags */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Used for BDs allocated by ddi_dma_mem_alloc()
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs 0, /* dma_attr_flags */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * PIO access attributes for registers
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * DMA access attributes for descriptors
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * DMA access attributes for data
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Property names
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic int rge_m_start(void *);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic void rge_m_stop(void *);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic int rge_m_multicst(void *, boolean_t, const uint8_t *);
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebstatic boolean_t rge_m_getcapab(void *, mac_capab_t, void *);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#define RGE_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate an area of memory and a DMA handle for accessing it
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_alloc_dma_mem(rge_t *rgep, size_t memsize, ddi_dma_attr_t *dma_attr_p,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, dma_area_t *dma_p)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate handle
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate memory
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Bind the two together
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Free one allocated area of DMAable memory
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Utility routine to carve a slice off a chunk of allocated memory,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * updating the chunk descriptor accordingly. The size of the slice
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * is given by the product of the <qty> and <size> parameters.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate memory & handle for packet statistics
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate memory & handle for Tx descriptor ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate memory & handle for Rx descriptor ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_free_bufs() -- free descriptors/buffers allocated for this
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * device instance.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Transmit and receive ring reinitialisation ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * These <reinit> routines each reset the rx/tx rings to an initial
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * state, assuming that the corresponding <init> routine has already
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * been called exactly once.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * re-init send ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* last BD in Tx ring */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * re-init receive ring
aa81749390e332985277568edab1ee6132326b42gs RGE_BSWAP_32(pbuf->cookie.dmac_laddress + rgep->head_room);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* last BD in Tx ring */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
aa81749390e332985277568edab1ee6132326b42gs * If all the up-sending buffers haven't been returned to driver,
aa81749390e332985277568edab1ee6132326b42gs * use bcopy() only in rx process.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
aa81749390e332985277568edab1ee6132326b42gs kmem_free(rgep->sw_sbds, RGE_SEND_SLOTS * sizeof (sw_sbd_t));
aa81749390e332985277568edab1ee6132326b42gsstatic void
aa81749390e332985277568edab1ee6132326b42gs kmem_free(rgep->sw_rbds, RGE_RECV_SLOTS * sizeof (sw_rbd_t));
aa81749390e332985277568edab1ee6132326b42gsstatic void
aa81749390e332985277568edab1ee6132326b42gs kmem_free(rgep->free_srbds, RGE_BUF_SLOTS * sizeof (sw_rbd_t));
aa81749390e332985277568edab1ee6132326b42gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate the array of s/w Tx Buffer Descriptors
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ssbdp = kmem_zalloc(RGE_SEND_SLOTS*sizeof (*ssbdp), KM_SLEEP);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Init send ring
aa81749390e332985277568edab1ee6132326b42gs rge_slice_chunk(&ssbdp->desc, &desc, 1, sizeof (rge_bd_t));
aa81749390e332985277568edab1ee6132326b42gs * Allocate memory & handle for Tx buffers
aa81749390e332985277568edab1ee6132326b42gs "rge_init_send_ring: alloc tx buffer failed");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate the array of s/w Rx Buffer Descriptors
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs srbdp = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*srbdp), KM_SLEEP);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Init receive ring
aa81749390e332985277568edab1ee6132326b42gs * Allocate memory & handle for Rx buffers
aa81749390e332985277568edab1ee6132326b42gs "rge_init_recv_ring: alloc rx buffer failed");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs "rge_init_recv_ring: desballoc() failed");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate the array of s/w free Buffer Descriptors
aa81749390e332985277568edab1ee6132326b42gs free_srbdp = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*free_srbdp), KM_SLEEP);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Init free buffer ring
aa81749390e332985277568edab1ee6132326b42gs * Allocate memory & handle for free Rx buffers
aa81749390e332985277568edab1ee6132326b42gs "rge_init_buf_ring: alloc rx free buffer failed");
aa81749390e332985277568edab1ee6132326b42gs "rge_init_buf_ring: desballoc() failed");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Internal state management entry points ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * These routines provide all the functionality required by the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * corresponding MAC layer entry points, but don't update the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * MAC state so they can be called internally without disturbing
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * our record of what NEMO thinks we should be doing ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_reset() -- reset h/w & rings to initial state
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Grab all the other mutexes in the world (this should
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ensure no other threads are manipulating driver state)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Free the world ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_stop() -- stop processing, don't reset h/w or rings
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_start() -- start transmitting/receiving
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Start chip processing, including enabling interrupts
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_restart - restart transmitting/receiving after error or suspend
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Wait for posted buffer to be freed...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
aa81749390e332985277568edab1ee6132326b42gs (void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Nemo-required management entry points ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_stop() -- stop transmitting/receiving
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Just stop processing, then record new MAC state
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Wait for posted buffer to be freed...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_start() -- start transmitting/receiving
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Clear hw/sw statistics
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Start processing and record new MAC state
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_unicst_set() -- set the physical network address
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Remember the new current address in the driver state
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Sync the chip's idea of the address too ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Compute the index of the required bit in the multicast hash map.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This must mirror the way the hardware actually does it!
aa81749390e332985277568edab1ee6132326b42gs /* the index value is between 0 and 63(0x3f) */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_multicst_add() -- enable/disable a multicast address
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
aa81749390e332985277568edab1ee6132326b42gs * Calculate the Multicast address hash index value
aa81749390e332985277568edab1ee6132326b42gs * Normally, the position of MAR0-MAR7 is
aa81749390e332985277568edab1ee6132326b42gs * MAR0: offset 0x08, ..., MAR7: offset 0x0F.
aa81749390e332985277568edab1ee6132326b42gs * For pcie chipset, the position of MAR0-MAR7 is
aa81749390e332985277568edab1ee6132326b42gs * different from others:
aa81749390e332985277568edab1ee6132326b42gs * MAR0: offset 0x0F, ..., MAR7: offset 0x08.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Set multicast register
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_promisc() -- set or reset promiscuous mode on the board
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Program the hardware to enable/disable promiscuous and/or
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * receive-all-multicast modes.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Store MAC layer specified mode and pass to chip layer to update h/w
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Loopback ioctl code
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * If the mode isn't being changed, there's nothing to do ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Validate the requested mode and prepare a suitable message
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * to explain the link down/up cycle that the change will
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * probably induce ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (mode) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * All OK; tell the caller to reprogram
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * the PHY and/or MAC for the new mode ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_loop_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Validate format of ioctl
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (cmd) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* NOTREACHED */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_error(rgep, "rge_loop_ioctl: invalid cmd 0x%x", cmd);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Specific rge IOCTLs, the MAC layer handles the generic ones.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
343c26163d86b7f3b861ae03b20226fecee1ab99mx * If suspended, we might actually be able to do some of
343c26163d86b7f3b861ae03b20226fecee1ab99mx * these ioctls, but it is harder to make sure they occur
343c26163d86b7f3b861ae03b20226fecee1ab99mx * without actually putting the hardware in an undesireable
343c26163d86b7f3b861ae03b20226fecee1ab99mx * state. So just NAK it.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Validate the command before bothering with the mutex ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (cmd) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* FALLTHRU */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* FALLTHRU */
aa81749390e332985277568edab1ee6132326b42gs * Check for specific net_config privilege
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (err != 0) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (cmd) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Do we need to reprogram the PHY and/or the MAC?
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Do it now, while we still have the mutex.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Note: update the PHY first, 'cos it controls the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * speed/duplex parameters that the MAC code uses.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (status) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Finally, decide how to reply
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (status) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Error, reply with a NAK and EINVAL or the specified error
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * OK, reply already sent
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * OK, reply with an ACK
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * OK, send prepared reply as ACK or NAK
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb/* ARGSUSED */
ba2e4443695ee6a6f420a35cd4fc3d3346d22932sebrge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China rge_t *rgep = arg;
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb switch (cap) {
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China switch (rgep->chipid.mac_ver) {
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8169:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8169S_D:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8169S_E:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8169SB:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8169SC:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8168:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8168B_B:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8168B_C:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8101E:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China *hcksum_txflags = HCKSUM_INET_FULL_V4 |
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China HCKSUM_IPHDRCKSUM;
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8101E_B:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China case MAC_VER_8101E_C:
834a2629f6f251c7492f75e808a856b82a27b337yong tan - Sun Microsystems - Beijing China *hcksum_txflags = 0;
aa81749390e332985277568edab1ee6132326b42gs * ============ Init MSI/Fixed Interrupt routines ==============
aa81749390e332985277568edab1ee6132326b42gs * rge_add_intrs:
aa81749390e332985277568edab1ee6132326b42gs * Register FIXED or MSI interrupts.
aa81749390e332985277568edab1ee6132326b42gs /* Get number of interrupts */
aa81749390e332985277568edab1ee6132326b42gs rge_error(rgep, "ddi_intr_get_nintrs() failure, ret: %d, "
aa81749390e332985277568edab1ee6132326b42gs /* Get number of available interrupts */
aa81749390e332985277568edab1ee6132326b42gs /* Allocate an array of interrupt handles */
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_alloc() */
aa81749390e332985277568edab1ee6132326b42gs rge_log(rgep, "ddi_intr_alloc() Requested: %d, Received: %d\n",
aa81749390e332985277568edab1ee6132326b42gs * Get priority for first msi, assume remaining are all the same
aa81749390e332985277568edab1ee6132326b42gs if ((ret = ddi_intr_get_pri(rgep->htable[0], &rgep->intr_pri)) !=
aa81749390e332985277568edab1ee6132326b42gs /* Free already allocated intr */
aa81749390e332985277568edab1ee6132326b42gs for (i = 0; i < actual; i++) {
aa81749390e332985277568edab1ee6132326b42gs /* Test for high level mutex */
aa81749390e332985277568edab1ee6132326b42gs "Hi level interrupt not supported");
aa81749390e332985277568edab1ee6132326b42gs for (i = 0; i < actual; i++)
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_add_handler() */
aa81749390e332985277568edab1ee6132326b42gs for (i = 0; i < actual; i++) {
aa81749390e332985277568edab1ee6132326b42gs if ((ret = ddi_intr_add_handler(rgep->htable[i], rge_intr,
aa81749390e332985277568edab1ee6132326b42gs /* Remove already added intr */
aa81749390e332985277568edab1ee6132326b42gs for (j = 0; j < i; j++)
aa81749390e332985277568edab1ee6132326b42gs /* Free already allocated intr */
aa81749390e332985277568edab1ee6132326b42gs for (i = 0; i < actual; i++) {
aa81749390e332985277568edab1ee6132326b42gs if ((ret = ddi_intr_get_cap(rgep->htable[0], &rgep->intr_cap))
aa81749390e332985277568edab1ee6132326b42gs for (i = 0; i < actual; i++) {
aa81749390e332985277568edab1ee6132326b42gs * rge_rem_intrs:
aa81749390e332985277568edab1ee6132326b42gs * Unregister FIXED or MSI interrupts
aa81749390e332985277568edab1ee6132326b42gsstatic void
aa81749390e332985277568edab1ee6132326b42gs /* Disable all interrupts */
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_block_disable() */
aa81749390e332985277568edab1ee6132326b42gs (void) ddi_intr_block_disable(rgep->htable, rgep->intr_cnt);
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_remove_handler() */
aa81749390e332985277568edab1ee6132326b42gs kmem_free(rgep->htable, rgep->intr_rqst * sizeof (ddi_intr_handle_t));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Per-instance setup/teardown code ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_INIT /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Flag that no more activity may be initiated
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Quiesce the PHY and MAC (leave it reset but still powered).
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Clean up and free all RGE data structures
343c26163d86b7f3b861ae03b20226fecee1ab99mx * If there are state inconsistancies, this is bad. Returning
343c26163d86b7f3b861ae03b20226fecee1ab99mx * DDI_FAILURE here will eventually cause the machine to panic,
343c26163d86b7f3b861ae03b20226fecee1ab99mx * so it is best done here so that there is a possibility of
343c26163d86b7f3b861ae03b20226fecee1ab99mx * debugging the problem.
343c26163d86b7f3b861ae03b20226fecee1ab99mx "rge: ngep returned from ddi_get_driver_private was NULL");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Refuse to resume if the data structures aren't consistent
343c26163d86b7f3b861ae03b20226fecee1ab99mx "rge: passed devinfo not the same as saved devinfo");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Read chip ID & set up config space command register(s)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Refuse to resume if the chip has changed its identity!
343c26163d86b7f3b861ae03b20226fecee1ab99mx * Only in one case, this conditional branch can be executed: the port
343c26163d86b7f3b861ae03b20226fecee1ab99mx * hasn't been plumbed.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * All OK, reinitialise h/w & kick off NEMO scheduling
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * attach(9E) -- Attach a device to the system
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Called once for each board successfully probed.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * we don't support high level interrupts in the driver
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs "rge_attach -- unsupported high level interrupt");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (cmd) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Initialize more fields in RGE private data
aa81749390e332985277568edab1ee6132326b42gs rgep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
aa81749390e332985277568edab1ee6132326b42gs rgep->msi_enable = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs (void) snprintf(rgep->ifname, sizeof (rgep->ifname), "%s%d",
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Map config space registers
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Read chip ID & set up config space command register(s)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Note: this leaves the chip accessible by Memory Space
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * accesses, but with interrupts and Bus Mastering off.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This should ensure that nothing untoward will happen
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * if it has been left active by the (net-)bootloader.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We'll re-enable Bus Mastering once we've reset the chip,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and allow interrupts only when everything else is set up.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Map operating registers
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China err = ddi_regs_map_setup(devinfo, 2, ®s,
5ca61e50c68a7a60dc35cd76831471faa4974d71Li-Zhen You * MMIO map will fail if the assigned address is bigger than 4G
5ca61e50c68a7a60dc35cd76831471faa4974d71Li-Zhen You * then choose I/O map
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Characterise the device, so we know its requirements.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Then allocate the appropriate TX and RX descriptors & buffers.
dfc2d53e07384b9eaca5466a2328c88a1ed96f32mx * Register NDD-tweakable parameters
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Add the softint handlers:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Both of these handlers are used to avoid restrictions on the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * context and/or mutexes required for some operations. In
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * particular, the hardware interrupt handler and its subfunctions
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * can detect a number of conditions that we don't want to handle
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * in that context or with that set of mutexes held. So, these
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * softints are triggered instead:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * the <resched> softint is triggered if if we have previously
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * had to refuse to send a packet because of resource shortage
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * (we've run out of transmit buffers), but the send completion
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * interrupt handler has now detected that more buffers have
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * become available.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * the <factotum> is triggered if the h/w interrupt handler
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * sees the <link state changed> or <error> bits in the status
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * block. It's also triggered periodically to poll the link
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * state, just in case we aren't getting link status change
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * interrupts ...
dd4eeefdb8e4583c47e28a7f315db6087931ef06eota DDI_INTR_SOFTPRI_MIN, rge_chip_factotum, (caddr_t)rgep);
aa81749390e332985277568edab1ee6132326b42gs * Get supported interrupt types
aa81749390e332985277568edab1ee6132326b42gs rge_error(rgep, "ddi_intr_get_supported_types failed\n");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Add the h/w interrupt handler and initialise mutexes
343c26163d86b7f3b861ae03b20226fecee1ab99mx * RTL8101E is observed to have MSI invalidation issue after S/R.
343c26163d86b7f3b861ae03b20226fecee1ab99mx * So the FIXED interrupt is used instead.
aa81749390e332985277568edab1ee6132326b42gs if ((intr_types & DDI_INTR_TYPE_MSI) && rgep->msi_enable) {
aa81749390e332985277568edab1ee6132326b42gs if (rge_add_intrs(rgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
aa81749390e332985277568edab1ee6132326b42gs "trying FIXED interrupt type\n");
aa81749390e332985277568edab1ee6132326b42gs if (rge_add_intrs(rgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
aa81749390e332985277568edab1ee6132326b42gs "registration failed\n");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Initialize rings
aa81749390e332985277568edab1ee6132326b42gs * Now that mutex locks are initialized, enable interrupts.
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_block_enable() for MSI interrupts */
aa81749390e332985277568edab1ee6132326b42gs (void) ddi_intr_block_enable(rgep->htable, rgep->intr_cnt);
aa81749390e332985277568edab1ee6132326b42gs /* Call ddi_intr_enable for MSI or FIXED interrupts */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Initialise link state variables
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Stop, reset & reinitialise the chip.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Initialise the (internal) PHY.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Reset chip & rings to initial state; also reset address
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * filtering, promiscuity, loopback mode.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Create & initialise named kstats
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Finally, we're ready to register ourselves with the MAC layer
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * interface; if this succeeds, we're all ready to start()
dd4eeefdb8e4583c47e28a7f315db6087931ef06eota * Register a periodical handler.
dd4eeefdb8e4583c47e28a7f315db6087931ef06eota * reg_chip_cyclic() is invoked in kernel context.
dd4eeefdb8e4583c47e28a7f315db6087931ef06eota rgep->periodic_id = ddi_periodic_add(rge_chip_cyclic, rgep,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_suspend() -- suspend transmit/receive for powerdown
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Stop processing and idle (powerdown) the PHY ...
368a5ef88e8811b10e03b912242c0faef12ce713Miles Xu, Sun Microsystems rw_enter(rgep->errlock, RW_WRITER);
193974072f41a843678abf5f61979c748687e66bSherry Moore * quiesce(9E) entry point.
193974072f41a843678abf5f61979c748687e66bSherry Moore * This function is called when the system is single-threaded at high
193974072f41a843678abf5f61979c748687e66bSherry Moore * PIL with preemption disabled. Therefore, this function must not be
193974072f41a843678abf5f61979c748687e66bSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
193974072f41a843678abf5f61979c748687e66bSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen.
193974072f41a843678abf5f61979c748687e66bSherry Moore * Turn off debugging
193974072f41a843678abf5f61979c748687e66bSherry Moore /* Stop the chip */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * detach(9E) -- Detach a device from the system
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_GTRACE(("rge_detach($%p, %d)", (void *)devinfo, cmd));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs switch (cmd) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * If there is any posted buffer, the driver should reject to be
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * detached. Need notice upper layer to release them.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Unregister from the MAC layer subsystem. This can fail, in
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * particular if there are DLPI style-2 streams still open -
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * in which case we just return failure without shutting
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * down chip operations.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * All activity stopped, so we can clean up & exit
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Module Loading Data & Entry Points ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_INIT /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsDDI_DEFINE_STREAM_OPS(rge_dev_ops, nulldev, nulldev, rge_attach, rge_detach,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs &mod_driverops, /* Type of module. This one is a driver */