mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-05-13 23:19:24 +08:00
parent
330f65f987
commit
de0badf2c3
@ -42,6 +42,7 @@ evdev = on
|
|||||||
fdt = on
|
fdt = on
|
||||||
fs_nfs = on
|
fs_nfs = on
|
||||||
fs_nfsclient = on
|
fs_nfsclient = on
|
||||||
|
if_mve = on
|
||||||
imx = on
|
imx = on
|
||||||
in_cksum = on
|
in_cksum = on
|
||||||
mdnsresponder = on
|
mdnsresponder = on
|
||||||
|
19
libbsd.py
19
libbsd.py
@ -816,6 +816,24 @@ class evdev(builder.Module):
|
|||||||
mm.generator['source']()
|
mm.generator['source']()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#
|
||||||
|
# MV643XX Ethernet driver
|
||||||
|
#
|
||||||
|
class if_mve(builder.Module):
|
||||||
|
|
||||||
|
def __init__(self, manager):
|
||||||
|
super(if_mve, self).__init__(manager, type(self).__name__)
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
mm = self.manager
|
||||||
|
self.addRTEMSKernelSourceFiles(
|
||||||
|
[
|
||||||
|
'sys/dev/mve/if_mve.c',
|
||||||
|
'sys/dev/mve/if_mve_nexus.c',
|
||||||
|
],
|
||||||
|
mm.generator['source']()
|
||||||
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
# USB
|
# USB
|
||||||
#
|
#
|
||||||
@ -5551,6 +5569,7 @@ def load(mm):
|
|||||||
mm.addModule(mmc_ti(mm))
|
mm.addModule(mmc_ti(mm))
|
||||||
mm.addModule(dev_input(mm))
|
mm.addModule(dev_input(mm))
|
||||||
mm.addModule(evdev(mm))
|
mm.addModule(evdev(mm))
|
||||||
|
mm.addModule(if_mve(mm))
|
||||||
|
|
||||||
mm.addModule(dev_usb(mm))
|
mm.addModule(dev_usb(mm))
|
||||||
mm.addModule(dev_usb_controller(mm))
|
mm.addModule(dev_usb_controller(mm))
|
||||||
|
397
rtemsbsd/include/bsp/mv643xx_eth.h
Normal file
397
rtemsbsd/include/bsp/mv643xx_eth.h
Normal file
@ -0,0 +1,397 @@
|
|||||||
|
/* Acknowledgement:
|
||||||
|
*
|
||||||
|
* Valuable information for developing this driver was obtained
|
||||||
|
* from the linux open-source driver mv643xx_eth.c which was written
|
||||||
|
* by the following people and organizations:
|
||||||
|
*
|
||||||
|
* Matthew Dharm <mdharm@momenco.com>
|
||||||
|
* rabeeh@galileo.co.il
|
||||||
|
* PMC-Sierra, Inc., Manish Lachwani
|
||||||
|
* Ralf Baechle <ralf@linux-mips.org>
|
||||||
|
* MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org>
|
||||||
|
* Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com>
|
||||||
|
*
|
||||||
|
* Note however, that in spite of the identical name of this file
|
||||||
|
* (and some of the symbols used herein) this file provides a
|
||||||
|
* new implementation and is the original work by the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Authorship
|
||||||
|
* ----------
|
||||||
|
* This software (mv643xx ethernet driver for RTEMS) was
|
||||||
|
* created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
|
||||||
|
* Stanford Linear Accelerator Center, Stanford University.
|
||||||
|
*
|
||||||
|
* Acknowledgement of sponsorship
|
||||||
|
* ------------------------------
|
||||||
|
* The 'mv643xx ethernet driver for RTEMS' was produced by
|
||||||
|
* the Stanford Linear Accelerator Center, Stanford University,
|
||||||
|
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
||||||
|
*
|
||||||
|
* Government disclaimer of liability
|
||||||
|
* ----------------------------------
|
||||||
|
* Neither the United States nor the United States Department of Energy,
|
||||||
|
* nor any of their employees, makes any warranty, express or implied, or
|
||||||
|
* assumes any legal liability or responsibility for the accuracy,
|
||||||
|
* completeness, or usefulness of any data, apparatus, product, or process
|
||||||
|
* disclosed, or represents that its use would not infringe privately owned
|
||||||
|
* rights.
|
||||||
|
*
|
||||||
|
* Stanford disclaimer of liability
|
||||||
|
* --------------------------------
|
||||||
|
* Stanford University makes no representations or warranties, express or
|
||||||
|
* implied, nor assumes any liability for the use of this software.
|
||||||
|
*
|
||||||
|
* Stanford disclaimer of copyright
|
||||||
|
* --------------------------------
|
||||||
|
* Stanford University, owner of the copyright, hereby disclaims its
|
||||||
|
* copyright and all other rights in this software. Hence, anyone may
|
||||||
|
* freely use it for any purpose without restriction.
|
||||||
|
*
|
||||||
|
* Maintenance of notices
|
||||||
|
* ----------------------
|
||||||
|
* In the interest of clarity regarding the origin and status of this
|
||||||
|
* SLAC software, this and all the preceding Stanford University notices
|
||||||
|
* are to remain affixed to any copy or derivative of this software made
|
||||||
|
* or distributed by the recipient and are to be affixed to any copy of
|
||||||
|
* software made or distributed by the recipient that contains a copy or
|
||||||
|
* derivative of this software.
|
||||||
|
*
|
||||||
|
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MV643XX_LOWLEVEL_DRIVER_H
|
||||||
|
#define MV643XX_LOWLEVEL_DRIVER_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MV643XXETH_NUM_DRIVER_SLOTS 2
|
||||||
|
|
||||||
|
struct mveth_private;
|
||||||
|
|
||||||
|
/* Create interface.
|
||||||
|
* Allocates resources for descriptor rings and sets up the driver software structure.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* unit:
|
||||||
|
* interface # (1..2). The interface must not be attached to BSD.
|
||||||
|
*
|
||||||
|
* driver_tid:
|
||||||
|
* optional driver task-id (can be retrieved with BSP_mve_get_tid()).
|
||||||
|
* Not used by the low-level driver.
|
||||||
|
*
|
||||||
|
* isr(isr_arg):
|
||||||
|
* user ISR.
|
||||||
|
*
|
||||||
|
* void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred):
|
||||||
|
* Pointer to user-supplied callback to release a buffer that had been sent
|
||||||
|
* by BSP_mve_send_buf() earlier. The callback is passed 'cleanup_txbuf_arg'
|
||||||
|
* and a flag indicating whether the send had been successful.
|
||||||
|
* The driver no longer accesses 'user_buf' after invoking this callback.
|
||||||
|
* CONTEXT: This callback is executed either by BSP_mve_swipe_tx() or
|
||||||
|
* BSP_mve_send_buf(), BSP_mve_init_hw(), BSP_mve_stop_hw() (the latter
|
||||||
|
* ones calling BSP_mve_swipe_tx()).
|
||||||
|
* void *cleanup_txbuf_arg:
|
||||||
|
* Closure argument that is passed on to 'cleanup_txbuf()' callback;
|
||||||
|
*
|
||||||
|
* void *(*alloc_rxbuf)(int *p_size, unsigned long *p_data_addr),
|
||||||
|
* Pointer to user-supplied callback to allocate a buffer for subsequent
|
||||||
|
* insertion into the RX ring by the driver.
|
||||||
|
* RETURNS: opaque handle to the buffer (which may be a more complex object
|
||||||
|
* such as an 'mbuf'). The handle is not used by the driver directly
|
||||||
|
* but passed back to the 'consume_rxbuf()' callback.
|
||||||
|
* Size of the available data area and pointer to buffer's data area
|
||||||
|
* in '*psize' and '*p_data_area', respectively.
|
||||||
|
* If no buffer is available, this routine should return NULL in which
|
||||||
|
* case the driver drops the last packet and re-uses the last buffer
|
||||||
|
* instead of handing it out to 'consume_rxbuf()'.
|
||||||
|
* CONTEXT: Called when initializing the RX ring (BSP_mve_init_hw()) or when
|
||||||
|
* swiping it (BSP_mve_swipe_rx()).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len);
|
||||||
|
* Pointer to user-supplied callback to pass a received buffer back to
|
||||||
|
* the user. The driver no longer accesses the buffer after invoking this
|
||||||
|
* callback (with 'len'>0, see below). 'user_buf' is the buffer handle
|
||||||
|
* previously generated by 'alloc_rxbuf()'.
|
||||||
|
* The callback is passed 'cleanup_rxbuf_arg' and a 'len'
|
||||||
|
* argument giving the number of bytes that were received.
|
||||||
|
* 'len' may be <=0 in which case the 'user_buf' argument is NULL.
|
||||||
|
* 'len' == 0 means that the last 'alloc_rxbuf()' had failed,
|
||||||
|
* 'len' < 0 indicates a receiver error. In both cases, the last packet
|
||||||
|
* was dropped/missed and the last buffer will be re-used by the driver.
|
||||||
|
* NOTE: the data are 'prefixed' with two bytes, i.e., the ethernet packet header
|
||||||
|
* is stored at offset 2 in the buffer's data area. Also, the FCS (4 bytes)
|
||||||
|
* is appended. 'len' accounts for both.
|
||||||
|
* CONTEXT: Called from BSP_mve_swipe_rx().
|
||||||
|
* void *cleanup_rxbuf_arg:
|
||||||
|
* Closure argument that is passed on to 'consume_rxbuf()' callback;
|
||||||
|
*
|
||||||
|
* rx_ring_size, tx_ring_size:
|
||||||
|
* How many big to make the RX and TX descriptor rings. Note that the sizes
|
||||||
|
* may be 0 in which case a reasonable default will be used.
|
||||||
|
* If either ring size is < 0 then the RX or TX will be disabled.
|
||||||
|
* Note that it is illegal in this case to use BSP_mve_swipe_rx() or
|
||||||
|
* BSP_mve_swipe_tx(), respectively.
|
||||||
|
*
|
||||||
|
* irq_mask:
|
||||||
|
* Interrupts to enable. OR of flags from above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Direct assignment of MVE flags to user API relies on irqs and x-irqs not overlapping */
|
||||||
|
#define MV643XX_ETH_IRQ_RX_DONE (1<<2)
|
||||||
|
#define MV643XX_ETH_EXT_IRQ_TX_DONE (1<<0)
|
||||||
|
#define MV643XX_ETH_EXT_IRQ_LINK_CHG (1<<16)
|
||||||
|
|
||||||
|
struct mveth_private *
|
||||||
|
BSP_mve_create(
|
||||||
|
int unit,
|
||||||
|
rtems_id tid,
|
||||||
|
void (*isr)(void*isr_arg),
|
||||||
|
void *isr_arg,
|
||||||
|
void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred),
|
||||||
|
void *cleanup_txbuf_arg,
|
||||||
|
void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
|
||||||
|
void (*consume_rxbuf)(void *user_buf, void *closure, int len),
|
||||||
|
void *consume_rxbuf_arg,
|
||||||
|
int rx_ring_size,
|
||||||
|
int tx_ring_size,
|
||||||
|
int irq_mask
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear multicast hash filter. No multicast frames are accepted
|
||||||
|
* after executing this routine (unless the hardware was initialized
|
||||||
|
* in 'promiscuous' mode).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_mcast_filter_clear(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Program multicast filter to accept all multicast frames
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_mcast_filter_accept_all(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a MAC address to the multicast filter.
|
||||||
|
* Existing entries are not changed but note that
|
||||||
|
* the filter is imperfect, i.e., multiple MAC addresses
|
||||||
|
* may alias to a single filter entry. Hence software
|
||||||
|
* filtering must still be performed.
|
||||||
|
*
|
||||||
|
* If a higher-level driver implements IP multicasting
|
||||||
|
* then multiple IP addresses may alias to the same MAC
|
||||||
|
* address. This driver maintains a 'reference-count'
|
||||||
|
* which is incremented every time the same MAC-address
|
||||||
|
* is passed to this routine; the address is only removed
|
||||||
|
* from the filter if BSP_mve_mcast_filter_accept_del()
|
||||||
|
* is called the same number of times (or by BSP_mve_mcast_filter_clear).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a MAC address from the multicast filter.
|
||||||
|
* This routine decrements the reference count of the given
|
||||||
|
* MAC-address and removes it from the filter once the
|
||||||
|
* count reaches zero.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr);
|
||||||
|
|
||||||
|
|
||||||
|
/* Enable/disable promiscuous mode */
|
||||||
|
void
|
||||||
|
BSP_mve_promisc_set(struct mveth_private *mp, int promisc);
|
||||||
|
|
||||||
|
/* calls BSP_mve_stop_hw(), releases all resources and marks the interface
|
||||||
|
* as unused.
|
||||||
|
* RETURNS 0 on success, nonzero on failure.
|
||||||
|
* NOTE: the handle MUST NOT be used after successful execution of this
|
||||||
|
* routine.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
BSP_mve_detach(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Enqueue a buffer chain for transmission.
|
||||||
|
*
|
||||||
|
* RETURN: #bytes sent or -1 if there are not enough descriptors
|
||||||
|
* -2 is returned if the caller should attempt to
|
||||||
|
* repackage the chain into a smaller one.
|
||||||
|
*
|
||||||
|
* Comments: software cache-flushing incurs a penalty if the
|
||||||
|
* packet cannot be queued since it is flushed anyways.
|
||||||
|
* The algorithm is slightly more efficient in the normal
|
||||||
|
* case, though.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct MveEthBufIter {
|
||||||
|
void *hdl; /* opaque handle for the iterator implementor */
|
||||||
|
void *data; /* data to be sent */
|
||||||
|
size_t len; /* data size (in octets) */
|
||||||
|
void *uptr; /* user-pointer to go into the descriptor;
|
||||||
|
note: cleanup_txbuf is only called for desriptors
|
||||||
|
where this field is non-NULL (for historical
|
||||||
|
reasons) */
|
||||||
|
} MveEthBufIter;
|
||||||
|
|
||||||
|
typedef MveEthBufIter *(*MveEthBufIterNext)(MveEthBufIter*);
|
||||||
|
|
||||||
|
int
|
||||||
|
BSP_mve_send_buf_chain(struct mveth_private *mp, MveEthBufIterNext next, MveEthBufIter *it);
|
||||||
|
|
||||||
|
|
||||||
|
/* Legacy entry point to send a header + a buffer */
|
||||||
|
int
|
||||||
|
BSP_mve_send_buf_raw(struct mveth_private *mp, void *head_p, int h_len, void *data_p, int d_len);
|
||||||
|
|
||||||
|
/* Descriptor scavenger; cleanup the TX ring, passing all buffers
|
||||||
|
* that have been sent to the cleanup_tx() callback.
|
||||||
|
* This routine is called from BSP_mve_send_buf(), BSP_mve_init_hw(),
|
||||||
|
* BSP_mve_stop_hw().
|
||||||
|
*
|
||||||
|
* RETURNS: number of buffers processed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
BSP_mve_swipe_tx(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Retrieve all received buffers from the RX ring, replacing them
|
||||||
|
* by fresh ones (obtained from the alloc_rxbuf() callback). The
|
||||||
|
* received buffers are passed to consume_rxbuf().
|
||||||
|
*
|
||||||
|
* RETURNS: number of buffers processed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
BSP_mve_swipe_rx(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* read ethernet address from hw to buffer */
|
||||||
|
void
|
||||||
|
BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr);
|
||||||
|
|
||||||
|
/* Interrupt related routines */
|
||||||
|
|
||||||
|
/* Note: the BSP_mve_enable/disable/ack_irqs() entry points
|
||||||
|
* are deprecated.
|
||||||
|
* The newer API where the user passes a mask allows
|
||||||
|
* for more selective control.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Enable all supported interrupts at device */
|
||||||
|
void
|
||||||
|
BSP_mve_enable_irqs(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Disable all supported interrupts at device */
|
||||||
|
void
|
||||||
|
BSP_mve_disable_irqs(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Acknowledge (and clear) all supported interrupts.
|
||||||
|
* RETURNS: interrupts that were raised.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
BSP_mve_ack_irqs(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Enable interrupts included in 'mask' (leaving
|
||||||
|
* already enabled interrupts on). If the mask
|
||||||
|
* includes bits that were not passed to the 'setup'
|
||||||
|
* routine then the behavior is undefined.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t irq_mask);
|
||||||
|
|
||||||
|
/* Disable interrupts included in 'mask' (leaving
|
||||||
|
* other ones that are currently enabled on). If the
|
||||||
|
* mask includes bits that were not passed to the 'setup'
|
||||||
|
* routine then the behavior is undefined.
|
||||||
|
*
|
||||||
|
* RETURNS: Bitmask of interrupts that were enabled upon entry
|
||||||
|
* into this routine. This can be used to restore the
|
||||||
|
* previous state.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t irq_mask);
|
||||||
|
|
||||||
|
/* Acknowledge and clear selected interrupts.
|
||||||
|
*
|
||||||
|
* RETURNS: All pending interrupts.
|
||||||
|
*
|
||||||
|
* NOTE: Only pending interrupts contained in 'mask'
|
||||||
|
* are cleared. Others are left pending.
|
||||||
|
*
|
||||||
|
* This routine can be used to check for pending
|
||||||
|
* interrupts (pass mask == 0) or to clear all
|
||||||
|
* interrupts (pass mask == -1).
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask);
|
||||||
|
|
||||||
|
/* Retrieve the driver daemon TID that was passed to
|
||||||
|
* BSP_mve_setup().
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_id
|
||||||
|
BSP_mve_get_tid(struct mveth_private *mp);
|
||||||
|
|
||||||
|
/* Dump statistics to file (stdout if NULL)
|
||||||
|
*
|
||||||
|
* NOTE: this routine is not thread safe
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_dump_stats(struct mveth_private *mp, FILE *f);
|
||||||
|
|
||||||
|
#define MV643XX_MEDIA_LINK (1<<0)
|
||||||
|
#define MV643XX_MEDIA_FD (1<<1)
|
||||||
|
#define MV643XX_MEDIA_10 (1<<8)
|
||||||
|
#define MV643XX_MEDIA_100 (2<<8)
|
||||||
|
#define MV643XX_MEDIA_1000 (3<<8)
|
||||||
|
#define MV643XX_MEDIA_SPEED_MSK (0xff00)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize interface hardware
|
||||||
|
*
|
||||||
|
* 'mp' handle obtained by from BSP_mve_setup().
|
||||||
|
* 'promisc' whether to set promiscuous flag.
|
||||||
|
* 'enaddr' pointer to six bytes with MAC address. Read
|
||||||
|
* from the device if NULL.
|
||||||
|
* 'speed' current speed and link status as read from the PHY.
|
||||||
|
*
|
||||||
|
* Note: Multicast filters are cleared by this routine.
|
||||||
|
* However, in promiscuous mode the mcast filters
|
||||||
|
* are programmed to accept all multicast frames.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr, int speed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the serial port to a new speed (e.g., result of a PHY IRQ)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_update_serial_port(struct mveth_private *mp, int speed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shutdown hardware and clean out the rings
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_mve_stop_hw(struct mveth_private *mp);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BSP_mve_mii_read(struct mveth_private *mp, unsigned addr);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BSP_mve_mii_write(struct mveth_private *mp, unsigned addr, unsigned v);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BSP_mve_mii_read_early(int port, unsigned addr);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BSP_mve_mii_write_early(int port, unsigned addr, unsigned v);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -266,6 +266,11 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
|
|||||||
RTEMS_BSD_DEFINE_NEXUS_DEVICE(fec, 0, 0, NULL);
|
RTEMS_BSD_DEFINE_NEXUS_DEVICE(fec, 0, 0, NULL);
|
||||||
SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
|
SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
|
||||||
|
|
||||||
|
#elif defined(LIBBSP_BEATNIK_BSP_H)
|
||||||
|
|
||||||
|
RTEMS_BSD_DEFINE_NEXUS_DEVICE(mve, 0, 0, NULL);
|
||||||
|
SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
|
||||||
|
|
||||||
#elif defined(LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H)
|
#elif defined(LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H)
|
||||||
|
|
||||||
RTEMS_BSD_DRIVER_PC_LEGACY;
|
RTEMS_BSD_DRIVER_PC_LEGACY;
|
||||||
|
2389
rtemsbsd/sys/dev/mve/if_mve.c
Normal file
2389
rtemsbsd/sys/dev/mve/if_mve.c
Normal file
File diff suppressed because it is too large
Load Diff
935
rtemsbsd/sys/dev/mve/if_mve_nexus.c
Normal file
935
rtemsbsd/sys/dev/mve/if_mve_nexus.c
Normal file
@ -0,0 +1,935 @@
|
|||||||
|
/* RTEMS driver for the mv643xx gigabit ethernet chip */
|
||||||
|
|
||||||
|
/* Acknowledgement:
|
||||||
|
*
|
||||||
|
* Valuable information for developing this driver was obtained
|
||||||
|
* from the linux open-source driver mv643xx_eth.c which was written
|
||||||
|
* by the following people and organizations:
|
||||||
|
*
|
||||||
|
* Matthew Dharm <mdharm@momenco.com>
|
||||||
|
* rabeeh@galileo.co.il
|
||||||
|
* PMC-Sierra, Inc., Manish Lachwani
|
||||||
|
* Ralf Baechle <ralf@linux-mips.org>
|
||||||
|
* MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org>
|
||||||
|
* Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com>
|
||||||
|
*
|
||||||
|
* Note however, that in spite of the identical name of this file
|
||||||
|
* (and some of the symbols used herein) this file provides a
|
||||||
|
* new implementation and is the original work by the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Authorship
|
||||||
|
* ----------
|
||||||
|
* This software (mv643xx ethernet driver for RTEMS) was
|
||||||
|
* created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
|
||||||
|
* Stanford Linear Accelerator Center, Stanford University.
|
||||||
|
*
|
||||||
|
* Acknowledgement of sponsorship
|
||||||
|
* ------------------------------
|
||||||
|
* The 'mv643xx ethernet driver for RTEMS' was produced by
|
||||||
|
* the Stanford Linear Accelerator Center, Stanford University,
|
||||||
|
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
||||||
|
*
|
||||||
|
* Government disclaimer of liability
|
||||||
|
* ----------------------------------
|
||||||
|
* Neither the United States nor the United States Department of Energy,
|
||||||
|
* nor any of their employees, makes any warranty, express or implied, or
|
||||||
|
* assumes any legal liability or responsibility for the accuracy,
|
||||||
|
* completeness, or usefulness of any data, apparatus, product, or process
|
||||||
|
* disclosed, or represents that its use would not infringe privately owned
|
||||||
|
* rights.
|
||||||
|
*
|
||||||
|
* Stanford disclaimer of liability
|
||||||
|
* --------------------------------
|
||||||
|
* Stanford University makes no representations or warranties, express or
|
||||||
|
* implied, nor assumes any liability for the use of this software.
|
||||||
|
*
|
||||||
|
* Stanford disclaimer of copyright
|
||||||
|
* --------------------------------
|
||||||
|
* Stanford University, owner of the copyright, hereby disclaims its
|
||||||
|
* copyright and all other rights in this software. Hence, anyone may
|
||||||
|
* freely use it for any purpose without restriction.
|
||||||
|
*
|
||||||
|
* Maintenance of notices
|
||||||
|
* ----------------------
|
||||||
|
* In the interest of clarity regarding the origin and status of this
|
||||||
|
* SLAC software, this and all the preceding Stanford University notices
|
||||||
|
* are to remain affixed to any copy or derivative of this software made
|
||||||
|
* or distributed by the recipient and are to be affixed to any copy of
|
||||||
|
* software made or distributed by the recipient that contains a copy or
|
||||||
|
* derivative of this software.
|
||||||
|
*
|
||||||
|
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Nexus port by Till Straumann, <till.straumann@psi.ch>, 3/2021 */
|
||||||
|
|
||||||
|
#include <machine/rtems-bsd-kernel-space.h>
|
||||||
|
#include <bsp.h>
|
||||||
|
|
||||||
|
#ifdef LIBBSP_BEATNIK_BSP_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#include <net/if_var.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/if_media.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <dev/mii/mii.h>
|
||||||
|
#include <dev/mii/miivar.h>
|
||||||
|
#include <rtems/bsd/local/miibus_if.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <bsp/mv643xx_eth.h>
|
||||||
|
|
||||||
|
#define DRVNAME "mv63xx_nexus"
|
||||||
|
|
||||||
|
#undef MVETH_DEBUG
|
||||||
|
|
||||||
|
/* Define default ring sizes */
|
||||||
|
|
||||||
|
#undef MVETH_TESTING
|
||||||
|
|
||||||
|
#ifdef MVETH_TESTING
|
||||||
|
/* hard and small defaults */
|
||||||
|
#define MV643XX_RX_RING_SIZE 2
|
||||||
|
#define MV643XX_TX_QUEUE_SIZE 4
|
||||||
|
#define MV643XX_BD_PER_PACKET 1
|
||||||
|
#define TX_LOWWATER 1
|
||||||
|
|
||||||
|
#else /* MVETH_TESTING */
|
||||||
|
|
||||||
|
#define MV643XX_RX_RING_SIZE 40 /* attached buffers are always 2k clusters, i.e., this
|
||||||
|
* driver - with a configured ring size of 40 - constantly
|
||||||
|
* locks 80k of cluster memory - your app config better
|
||||||
|
* provides enough space!
|
||||||
|
*/
|
||||||
|
#define MV643XX_TX_QUEUE_SIZE 40
|
||||||
|
#define MV643XX_BD_PER_PACKET 10
|
||||||
|
#define TX_LOWWATER (4*(MV643XX_BD_PER_PACKET))
|
||||||
|
#endif /* MVETH_TESTING */
|
||||||
|
|
||||||
|
/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain;
|
||||||
|
* I observed chains of >17 entries regularly!
|
||||||
|
*/
|
||||||
|
#define MV643XX_TX_RING_SIZE ((MV643XX_TX_QUEUE_SIZE) * (MV643XX_BD_PER_PACKET))
|
||||||
|
|
||||||
|
/* The chip puts the ethernet header at offset 2 into the buffer so
|
||||||
|
* that the payload is aligned
|
||||||
|
*/
|
||||||
|
#define ETH_RX_OFFSET 2
|
||||||
|
#define ETH_CRC_LEN 4 /* strip FCS at end of packet */
|
||||||
|
|
||||||
|
#ifndef __PPC__
|
||||||
|
#error "Dont' know how to deal with cache on this CPU architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency
|
||||||
|
* management works for cache line sizes of 16 and 32 bytes only. If the line size
|
||||||
|
* is bigger, the descriptors could be padded...
|
||||||
|
*/
|
||||||
|
#if !defined(PPC_CACHE_ALIGNMENT)
|
||||||
|
#error "PPC_CACHE_ALIGNMENT not defined"
|
||||||
|
#elif PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
|
||||||
|
#error "Cache line size must be 16 or 32"
|
||||||
|
#else
|
||||||
|
#define RX_BUF_ALIGNMENT PPC_CACHE_ALIGNMENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* HELPER MACROS */
|
||||||
|
|
||||||
|
/* Align base to alignment 'a' */
|
||||||
|
#define MV643XX_ALIGN(b, a) ((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
|
||||||
|
|
||||||
|
|
||||||
|
#define IRQ_EVENT RTEMS_EVENT_0
|
||||||
|
#define TX_EVENT RTEMS_EVENT_1
|
||||||
|
|
||||||
|
/* Hacks -- FIXME */
|
||||||
|
rtems_id
|
||||||
|
rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg);
|
||||||
|
#define SIO_RTEMS_SHOW_STATS _IO('i', 250)
|
||||||
|
|
||||||
|
#define MVE643XX_DUMMY_PHY 0 /* phy is defined by low-level driver */
|
||||||
|
|
||||||
|
struct mve_enet_softc {
|
||||||
|
device_t dev;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
device_t miibus;
|
||||||
|
struct mii_data *mii_softc;
|
||||||
|
struct mveth_private *mp;
|
||||||
|
struct mtx mtx;
|
||||||
|
struct callout wdCallout;
|
||||||
|
rtems_id daemonTid;
|
||||||
|
int oif_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mve_enet_softc * ifaces[MV643XXETH_NUM_DRIVER_SLOTS] = { 0 };
|
||||||
|
|
||||||
|
typedef struct MveMbufIter {
|
||||||
|
MveEthBufIter it;
|
||||||
|
struct mbuf *next;
|
||||||
|
struct mbuf *head;
|
||||||
|
} MveMbufIter;
|
||||||
|
|
||||||
|
/* Forward Declarations */
|
||||||
|
struct mve_enet_softc;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr);
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_media_change(struct ifnet *ifp);
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_set_filters(struct ifnet *ifp);
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlateMediaFlags(const struct mii_data *mid);
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_ack_link_change(struct mve_enet_softc *sc);
|
||||||
|
|
||||||
|
static __inline__ void
|
||||||
|
mve_send_event(struct mve_enet_softc *sc, rtems_event_set ev)
|
||||||
|
{
|
||||||
|
rtems_status_code st;
|
||||||
|
if ( RTEMS_SUCCESSFUL != (st = rtems_event_send(sc->daemonTid, ev)) ) {
|
||||||
|
printk(DRVNAME": rtems_event_send returned 0x%08x (TID: 0x%08x, sc: 0x%08x)\n", st, sc->daemonTid, sc);
|
||||||
|
rtems_panic(DRVNAME": rtems_event_send() failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void
|
||||||
|
mve_lock(struct mve_enet_softc *sc, const char *from)
|
||||||
|
{
|
||||||
|
mtx_lock( & sc->mtx );
|
||||||
|
/*printk("L V %s\n", from);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void
|
||||||
|
mve_unlock(struct mve_enet_softc *sc, const char *from)
|
||||||
|
{
|
||||||
|
/*printk("L ^ %s\n", from);*/
|
||||||
|
mtx_unlock( & sc->mtx );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_probe(device_t dev)
|
||||||
|
{
|
||||||
|
int unit = device_get_unit(dev);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_probe (entering)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( unit >= 0 && unit < MV643XXETH_NUM_DRIVER_SLOTS ) {
|
||||||
|
err = BUS_PROBE_DEFAULT;
|
||||||
|
} else {
|
||||||
|
err = ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* starting at 'm' scan the buffer chain until we
|
||||||
|
* find a non-empty buffer (which we return)
|
||||||
|
*/
|
||||||
|
static __inline__ struct mbuf *
|
||||||
|
skipEmpty(struct mbuf *m)
|
||||||
|
{
|
||||||
|
while ( m && ( 0 == m->m_len ) ) {
|
||||||
|
m = m->m_next;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record a buffer's info in the low-leve driver 'iterator' struct.
|
||||||
|
* Also scan ahead to find the next non-empty buffer (store it in
|
||||||
|
* the iterator's 'next' field). This info is needed because we
|
||||||
|
* want to know if 'this' buffer is the last (non-empty!) one
|
||||||
|
* in a chain.
|
||||||
|
*
|
||||||
|
* On entry 'it->next' identifies 'this' buffer and on return
|
||||||
|
* 'it->next' points to the next non-empty buffer.
|
||||||
|
*/
|
||||||
|
static MveEthBufIter *
|
||||||
|
nextBuf(MveEthBufIter *arg)
|
||||||
|
{
|
||||||
|
MveMbufIter *it = (MveMbufIter*)arg;
|
||||||
|
struct mbuf *m;
|
||||||
|
/* If 'this' buffer is non-null */
|
||||||
|
if ( (m = it->next) ) {
|
||||||
|
/* find next non-empty buffer */
|
||||||
|
it->next = skipEmpty( m->m_next );
|
||||||
|
/* record 'this' buffer's info */
|
||||||
|
it->it.data = mtod(m, void*);
|
||||||
|
it->it.len = m->m_len;
|
||||||
|
/* if there is a non-empty buffer after 'this' uptr is NULL
|
||||||
|
* if this is tha last buffer in a chain then record the
|
||||||
|
* head of the chain in the uptr (for eventual cleanup
|
||||||
|
* by release_tx_mbuf()).
|
||||||
|
*/
|
||||||
|
it->it.uptr = it->next ? 0 : it->head;
|
||||||
|
return (MveEthBufIter*)it;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the iterator struct
|
||||||
|
*/
|
||||||
|
static MveEthBufIter *
|
||||||
|
initIter(MveMbufIter *it, struct mbuf *m)
|
||||||
|
{
|
||||||
|
/* record the head of the chain */
|
||||||
|
it->head = m;
|
||||||
|
/* initialize 'next' field to the first non-empty buffer.
|
||||||
|
* This may be NULL if the chain is entirely empty but
|
||||||
|
* that is handled correctly.
|
||||||
|
*/
|
||||||
|
it->next = skipEmpty( m );
|
||||||
|
/* Fill with first buf info */
|
||||||
|
return nextBuf( &it->it );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_send_mbuf( struct mve_enet_softc *sc, struct mbuf *m_head )
|
||||||
|
{
|
||||||
|
MveMbufIter iter;
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
if ( ! m_head ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! initIter( &iter, m_head ) ) {
|
||||||
|
/* completely empty chain */
|
||||||
|
m_freem( m_head );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rval = BSP_mve_send_buf_chain( sc->mp, nextBuf, &iter.it );
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_isr(void *closure)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*)closure;
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_isr; posting event to %x\n", sc->daemonTid);
|
||||||
|
#endif
|
||||||
|
BSP_mve_disable_irqs( sc->mp );
|
||||||
|
mve_send_event( sc, IRQ_EVENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_stop(struct mve_enet_softc *sc)
|
||||||
|
{
|
||||||
|
BSP_mve_stop_hw( sc->mp );
|
||||||
|
/* clear IF flags */
|
||||||
|
if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_set_filters(struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp );
|
||||||
|
int iff = if_getflags(ifp);
|
||||||
|
struct ifmultiaddr *ifma;
|
||||||
|
unsigned char *lladdr;
|
||||||
|
|
||||||
|
BSP_mve_promisc_set( sc->mp, !!(iff & IFF_PROMISC));
|
||||||
|
|
||||||
|
if ( iff & (IFF_PROMISC | IFF_ALLMULTI) ) {
|
||||||
|
BSP_mve_mcast_filter_accept_all(sc->mp);
|
||||||
|
} else {
|
||||||
|
BSP_mve_mcast_filter_clear( sc->mp );
|
||||||
|
|
||||||
|
if_maddr_rlock( ifp );
|
||||||
|
|
||||||
|
CK_STAILQ_FOREACH( ifma, &ifp->if_multiaddrs, ifma_link ) {
|
||||||
|
|
||||||
|
if ( ifma->ifma_addr->sa_family != AF_LINK ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lladdr = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
|
||||||
|
|
||||||
|
BSP_mve_mcast_filter_accept_add( sc->mp, lladdr );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if_maddr_runlock( ifp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Daemon task does all the 'interrupt' work */
|
||||||
|
static void
|
||||||
|
mve_daemon(void *arg)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) arg;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
|
rtems_event_set evs;
|
||||||
|
struct mbuf *m;
|
||||||
|
int avail;
|
||||||
|
int sndStat;
|
||||||
|
uint32_t irqstat;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": bsdnet mveth_daemon started\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mve_lock( sc, "daemon" );
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
mve_unlock( sc, "daemon" );
|
||||||
|
if ( RTEMS_SUCCESSFUL != rtems_event_receive( (IRQ_EVENT | TX_EVENT), (RTEMS_WAIT | RTEMS_EVENT_ANY), RTEMS_NO_TIMEOUT, &evs ) ) {
|
||||||
|
rtems_panic(DRVNAME": rtems_event_receive() failed!\n");
|
||||||
|
}
|
||||||
|
mve_lock( sc, "daemon" );
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": bsdnet mveth_daemon event received 0x%x\n", evs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( !(if_getflags(ifp) & IFF_UP) ) {
|
||||||
|
mve_stop(sc);
|
||||||
|
/* clear flag */
|
||||||
|
if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! (if_getdrvflags(ifp) & IFF_DRV_RUNNING) ) {
|
||||||
|
/* event could have been pending at the time hw was stopped;
|
||||||
|
* just ignore...
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (evs & IRQ_EVENT) ) {
|
||||||
|
irqstat = BSP_mve_ack_irqs(sc->mp);
|
||||||
|
} else {
|
||||||
|
irqstat = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) && sc->mii_softc ) {
|
||||||
|
/* phy status changed */
|
||||||
|
mii_pollstat( sc->mii_softc );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free tx chain and send */
|
||||||
|
if ( (evs & TX_EVENT) || (MV643XX_ETH_EXT_IRQ_TX_DONE & irqstat) ) {
|
||||||
|
while ( (avail = BSP_mve_swipe_tx( sc->mp )) > TX_LOWWATER ) {
|
||||||
|
IF_DEQUEUE( &ifp->if_snd, m );
|
||||||
|
if ( ! m ) {
|
||||||
|
/* clear active bit */
|
||||||
|
if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sndStat = mve_send_mbuf( sc, m );
|
||||||
|
if ( sndStat < 0 ) {
|
||||||
|
/* maybe not enough space right now; requeue and wait for next IRQ */
|
||||||
|
IF_PREPEND( &ifp->if_snd, m );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( (MV643XX_ETH_IRQ_RX_DONE & irqstat) ) {
|
||||||
|
BSP_mve_swipe_rx(sc->mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
BSP_mve_enable_irqs(sc->mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
mve_unlock( sc, "daemon (xit)" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
release_tx_mbuf(void *user_buf, void *closure, int error_on_tx_occurred)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*)closure;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
|
struct mbuf *mb = (struct mbuf*)user_buf;
|
||||||
|
|
||||||
|
if ( error_on_tx_occurred ) {
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_OERRORS, 1 );
|
||||||
|
} else {
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_OPACKETS, 1 );
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_OBYTES, mb->m_pkthdr.len );
|
||||||
|
}
|
||||||
|
m_freem(mb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
alloc_rx_mbuf(int *p_size, uintptr_t *p_data)
|
||||||
|
{
|
||||||
|
struct mbuf *m;
|
||||||
|
unsigned long l,o;
|
||||||
|
|
||||||
|
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
|
||||||
|
|
||||||
|
if ( m ) {
|
||||||
|
|
||||||
|
o = mtod(m, unsigned long);
|
||||||
|
l = MV643XX_ALIGN(o, RX_BUF_ALIGNMENT) - o;
|
||||||
|
|
||||||
|
/* align start of buffer */
|
||||||
|
m->m_data += l;
|
||||||
|
|
||||||
|
/* reduced length */
|
||||||
|
l = MCLBYTES - l;
|
||||||
|
|
||||||
|
m->m_len = m->m_pkthdr.len = l;
|
||||||
|
*p_size = m->m_len;
|
||||||
|
*p_data = mtod(m, uintptr_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*) m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
consume_rx_mbuf(void *user_buf, void *closure, int len)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*)closure;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
|
struct mbuf *m = (struct mbuf*)user_buf;
|
||||||
|
|
||||||
|
if ( len <= 0 ) {
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_IQDROPS, 1 );
|
||||||
|
if ( len < 0 ) {
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_IERRORS, 1 );
|
||||||
|
}
|
||||||
|
m_freem(m);
|
||||||
|
} else {
|
||||||
|
m->m_len = m->m_pkthdr.len = len - ETH_RX_OFFSET - ETH_CRC_LEN;
|
||||||
|
m->m_data += ETH_RX_OFFSET;
|
||||||
|
m->m_pkthdr.rcvif = ifp;
|
||||||
|
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_IPACKETS, 1 );
|
||||||
|
if_inc_counter( ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len );
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
/* Low-level debugging */
|
||||||
|
int i;
|
||||||
|
for (i=0; i<m->m_len; i++) {
|
||||||
|
if ( !(i&15) )
|
||||||
|
printk("\n");
|
||||||
|
printk("0x%02x ",mtod(m,char*)[i]);
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
mve_unlock( sc, "rx_cleanup" );
|
||||||
|
(*ifp->if_input)(ifp, m);
|
||||||
|
mve_lock( sc, "rx_cleanup" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Translate IFFLAGS to low-level driver representation */
|
||||||
|
static int
|
||||||
|
xlateMediaFlags(const struct mii_data *mid)
|
||||||
|
{
|
||||||
|
int lowLevelFlags = 0;
|
||||||
|
int msk = IFM_AVALID | IFM_ACTIVE;
|
||||||
|
|
||||||
|
if ( (mid->mii_media_status & msk) == msk ) {
|
||||||
|
lowLevelFlags |= MV643XX_MEDIA_LINK;
|
||||||
|
|
||||||
|
if ( IFM_OPTIONS( mid->mii_media_active ) & IFM_FDX ) {
|
||||||
|
lowLevelFlags |= MV643XX_MEDIA_FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( IFM_ETHER_SUBTYPE_GET( mid->mii_media_active ) ) {
|
||||||
|
default:
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME"xlateMediaFlags: UNKNOWN SPEED\n");
|
||||||
|
#endif
|
||||||
|
break; /* UNKNOWN -- FIXME */
|
||||||
|
case IFM_10_T:
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME"xlateMediaFlags: 10baseT\n");
|
||||||
|
#endif
|
||||||
|
lowLevelFlags |= MV643XX_MEDIA_10;
|
||||||
|
break;
|
||||||
|
case IFM_100_TX:
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME"xlateMediaFlags: 100baseT\n");
|
||||||
|
#endif
|
||||||
|
lowLevelFlags |= MV643XX_MEDIA_100;
|
||||||
|
break;
|
||||||
|
case IFM_1000_T:
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME"xlateMediaFlags: 1000baseT\n");
|
||||||
|
#endif
|
||||||
|
lowLevelFlags |= MV643XX_MEDIA_1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME"xlateMediaFlags: NO LINK\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return lowLevelFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_init(void *arg)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*)arg;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
|
int lowLevelMediaStatus = 0;
|
||||||
|
int promisc;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_init (entering)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( sc->mii_softc ) {
|
||||||
|
mii_pollstat( sc->mii_softc );
|
||||||
|
lowLevelMediaStatus = xlateMediaFlags( sc->mii_softc );
|
||||||
|
if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) {
|
||||||
|
if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
|
||||||
|
} else {
|
||||||
|
if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
promisc = !! (if_getdrvflags(ifp) & IFF_PROMISC);
|
||||||
|
|
||||||
|
BSP_mve_init_hw(sc->mp, promisc, if_getlladdr(ifp), lowLevelMediaStatus);
|
||||||
|
|
||||||
|
/* if promiscuous then there is no need to change */
|
||||||
|
if ( ! promisc ) {
|
||||||
|
mve_set_filters(ifp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_start(struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp );
|
||||||
|
mve_lock( sc, "mve_start" );
|
||||||
|
if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
|
||||||
|
mve_unlock( sc, "mve_start" );
|
||||||
|
mve_send_event( sc, TX_EVENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp );
|
||||||
|
struct ifreq *ifr = (struct ifreq *)data;
|
||||||
|
int err = 0;
|
||||||
|
int f, df;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_ioctl (entering)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mve_lock( sc, "mve_ioctl" );
|
||||||
|
|
||||||
|
switch ( cmd ) {
|
||||||
|
case SIOCSIFFLAGS:
|
||||||
|
f = if_getflags( ifp );
|
||||||
|
df = if_getdrvflags( ifp );
|
||||||
|
if ( (f & IFF_UP) ) {
|
||||||
|
if ( ! ( df & IFF_DRV_RUNNING ) ) {
|
||||||
|
mve_init( (void*)sc );
|
||||||
|
} else {
|
||||||
|
if ( (f & IFF_PROMISC) != (sc->oif_flags & IFF_PROMISC) ) {
|
||||||
|
mve_set_filters(ifp);
|
||||||
|
}
|
||||||
|
/* FIXME: other flag changes are ignored/unimplemented */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( df & IFF_DRV_RUNNING ) {
|
||||||
|
mve_stop(sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sc->oif_flags = f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIOCGIFMEDIA:
|
||||||
|
case SIOCSIFMEDIA:
|
||||||
|
if ( sc->mii_softc ) {
|
||||||
|
err = ifmedia_ioctl( ifp, ifr, &sc->mii_softc->mii_media, cmd );
|
||||||
|
} else {
|
||||||
|
err = EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIOCADDMULTI:
|
||||||
|
case SIOCDELMULTI:
|
||||||
|
if ( if_getdrvflags( ifp ) & IFF_DRV_RUNNING ) {
|
||||||
|
mve_set_filters(ifp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIO_RTEMS_SHOW_STATS:
|
||||||
|
BSP_mve_dump_stats(sc->mp, stdout);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = ether_ioctl(ifp, cmd, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mve_unlock( sc, "mve_ioctl" );
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SIO RTEMS_SHOW_STATS is too cumbersome to use -- for debugging, provide direct hack */
|
||||||
|
int
|
||||||
|
mv643xx_nexus_dump_stats(int unit, FILE *f)
|
||||||
|
{
|
||||||
|
if ( unit < 0 || unit >= MV643XXETH_NUM_DRIVER_SLOTS || ! ifaces[unit] )
|
||||||
|
return -EINVAL;
|
||||||
|
if ( ! f )
|
||||||
|
f = stdout;
|
||||||
|
BSP_mve_dump_stats(ifaces[unit]->mp, f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to update speed settings in the hardware
|
||||||
|
* when the phy setup changes.
|
||||||
|
*
|
||||||
|
* ASSUME: caller holds lock
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mve_ack_link_change(struct mve_enet_softc *sc)
|
||||||
|
{
|
||||||
|
struct mii_data *mii = sc->mii_softc;
|
||||||
|
int lowLevelMediaStatus;
|
||||||
|
|
||||||
|
if ( !mii )
|
||||||
|
return;
|
||||||
|
|
||||||
|
lowLevelMediaStatus = xlateMediaFlags( mii );
|
||||||
|
|
||||||
|
if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) {
|
||||||
|
BSP_mve_update_serial_port( sc->mp, lowLevelMediaStatus );
|
||||||
|
if_setdrvflagbits( sc->ifp, 0, IFF_DRV_OACTIVE );
|
||||||
|
mve_start( sc->ifp );
|
||||||
|
} else {
|
||||||
|
if_setdrvflagbits( sc->ifp, IFF_DRV_OACTIVE, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback from ifmedia_ioctl()
|
||||||
|
*
|
||||||
|
* Caller probably holds the lock already but
|
||||||
|
* since it is recursive we may as well make sure
|
||||||
|
* in case there are other possible execution paths.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mve_media_change(struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp );
|
||||||
|
struct mii_data *mii = sc->mii_softc;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_media_change\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ! mii ) {
|
||||||
|
return ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mii_mediachg( mii );
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp );
|
||||||
|
struct mii_data *mii = sc->mii_softc;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_media_status\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( mii ) {
|
||||||
|
mii_pollstat( mii );
|
||||||
|
ifmr->ifm_active = mii->mii_media_active;
|
||||||
|
ifmr->ifm_status = mii->mii_media_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_attach(device_t dev)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
uint8_t hwaddr[ETHER_ADDR_LEN];
|
||||||
|
struct mveth_private *mp;
|
||||||
|
int unit = device_get_unit(dev);
|
||||||
|
int tx_ring_size = MV643XX_TX_RING_SIZE;
|
||||||
|
int rx_ring_size = MV643XX_RX_RING_SIZE;
|
||||||
|
int tx_q_size = MV643XX_TX_QUEUE_SIZE;
|
||||||
|
|
||||||
|
sc = device_get_softc( dev );
|
||||||
|
sc->dev = dev;
|
||||||
|
sc->ifp = ifp = if_alloc(IFT_ETHER);
|
||||||
|
sc->daemonTid = 0;
|
||||||
|
sc->mii_softc = 0;
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_attach (entering)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mtx_init( &sc->mtx, device_get_nameunit( sc->dev ), MTX_NETWORK_LOCK, MTX_RECURSE );
|
||||||
|
callout_init_mtx( &sc->wdCallout, &sc->mtx, 0 );
|
||||||
|
|
||||||
|
if_setsoftc ( ifp, sc );
|
||||||
|
if_initname ( ifp, device_get_name(dev), unit);
|
||||||
|
if_setinitfn ( ifp, mve_init );
|
||||||
|
if_setioctlfn ( ifp, mve_ioctl );
|
||||||
|
if_setstartfn ( ifp, mve_start );
|
||||||
|
if_setflags ( ifp, (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX) );
|
||||||
|
sc->oif_flags = if_getflags( ifp );
|
||||||
|
|
||||||
|
if_setsendqlen ( ifp, tx_q_size );
|
||||||
|
if_setsendqready( ifp );
|
||||||
|
|
||||||
|
mp = BSP_mve_create(
|
||||||
|
unit + 1, /* low-level driver' unit numbers are 1-based */
|
||||||
|
0,
|
||||||
|
mve_isr, (void*)sc,
|
||||||
|
release_tx_mbuf, (void*)sc,
|
||||||
|
alloc_rx_mbuf,
|
||||||
|
consume_rx_mbuf, (void*)sc,
|
||||||
|
rx_ring_size,
|
||||||
|
tx_ring_size,
|
||||||
|
( MV643XX_ETH_IRQ_RX_DONE
|
||||||
|
| MV643XX_ETH_EXT_IRQ_TX_DONE
|
||||||
|
| MV643XX_ETH_EXT_IRQ_LINK_CHG));
|
||||||
|
|
||||||
|
if ( ! mp ) {
|
||||||
|
rtems_panic("Unable to create mv643xx low-level driver");
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->mp = mp;
|
||||||
|
|
||||||
|
BSP_mve_read_eaddr( mp, hwaddr );
|
||||||
|
|
||||||
|
if ( 0 == mii_attach( sc->dev,
|
||||||
|
&sc->miibus,
|
||||||
|
ifp,
|
||||||
|
mve_media_change,
|
||||||
|
mve_media_status,
|
||||||
|
BMSR_DEFCAPMASK,
|
||||||
|
MVE643XX_DUMMY_PHY,
|
||||||
|
MII_OFFSET_ANY,
|
||||||
|
0 ) ) {
|
||||||
|
sc->mii_softc = device_get_softc( sc->miibus );
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->daemonTid = rtems_bsdnet_newproc("MVE", 4096, mve_daemon, (void*)sc);
|
||||||
|
|
||||||
|
ether_ifattach( ifp, hwaddr );
|
||||||
|
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_attach (leaving)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ifaces[unit] = sc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_miibus_read_reg(device_t dev, int phy, int reg)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev);
|
||||||
|
|
||||||
|
/* low-level driver knows what phy to use; ignore arg */
|
||||||
|
return (int) BSP_mve_mii_read( sc->mp, reg );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mve_miibus_write_reg(device_t dev, int phy, int reg, int val)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev);
|
||||||
|
|
||||||
|
/* low-level driver knows what phy to use; ignore arg */
|
||||||
|
BSP_mve_mii_write( sc->mp, reg, val );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_miibus_statchg(device_t dev)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev);
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_miibus_statchg\n");
|
||||||
|
#endif
|
||||||
|
/* assume this ends up being called either from the ioctl or the driver
|
||||||
|
* task -- either of which holds the lock.
|
||||||
|
*/
|
||||||
|
mve_ack_link_change( sc );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mve_miibus_linkchg(device_t dev)
|
||||||
|
{
|
||||||
|
struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev);
|
||||||
|
#ifdef MVETH_DEBUG
|
||||||
|
printk(DRVNAME": mve_miibus_linkchg\n");
|
||||||
|
#endif
|
||||||
|
/* assume this ends up being called either from the ioctl or the driver
|
||||||
|
* task -- either of which holds the lock.
|
||||||
|
*/
|
||||||
|
mve_ack_link_change( sc );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static device_method_t mve_methods[] = {
|
||||||
|
DEVMETHOD(device_probe, mve_probe ),
|
||||||
|
DEVMETHOD(device_attach, mve_attach),
|
||||||
|
|
||||||
|
DEVMETHOD(miibus_readreg, mve_miibus_read_reg ),
|
||||||
|
DEVMETHOD(miibus_writereg, mve_miibus_write_reg),
|
||||||
|
DEVMETHOD(miibus_statchg , mve_miibus_statchg ),
|
||||||
|
DEVMETHOD(miibus_linkchg , mve_miibus_linkchg ),
|
||||||
|
|
||||||
|
DEVMETHOD_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t mve_nexus_driver = {
|
||||||
|
"mve",
|
||||||
|
mve_methods,
|
||||||
|
sizeof( struct mve_enet_softc )
|
||||||
|
};
|
||||||
|
|
||||||
|
static devclass_t mve_devclass;
|
||||||
|
|
||||||
|
DRIVER_MODULE(mve, nexus, mve_nexus_driver, mve_devclass, 0, 0);
|
||||||
|
DRIVER_MODULE(miibus, mve, miibus_driver, miibus_devclass, 0, 0);
|
||||||
|
|
||||||
|
MODULE_DEPEND(mve, nexus, 1, 1, 1);
|
||||||
|
MODULE_DEPEND(mve, ether, 1, 1, 1);
|
||||||
|
|
||||||
|
#endif /* LIBBSP_BEATNIK_BSP_H */
|
Loading…
x
Reference in New Issue
Block a user