Commit 18dcb14a authored by Miguel Jimenez Lopez's avatar Miguel Jimenez Lopez

Merge changes from "adam-wr-nic-rebased" branch.

parent 36f70fe4
......@@ -659,6 +659,10 @@ The module receives the following parameters:
The name of the LM32 program to load, if any. There is no support
currently to load different LM32 programs to different cards.
@item macaddr=
Use given MAC address. If not provided or 0 read MAC from LM32.
@end table
@c ==========================================================================
......@@ -743,6 +747,9 @@ following:
ifconfig wr0 hw ether 12:34:56:78:9a:bc
@end example
MAC address can also be set by using @code{macaddr=} parameter
at load of @i{wr-nic} kernel module.
The fiber controlled by the SPEC can carry normal data traffic in
addition to the PTP frames of @i{White Rabbit}, that remain
invisible to the host computer. The
......
......@@ -18,6 +18,7 @@ LINUXINCLUDE := -I$(FMC_BUS_ABS)/kernel/include -I$(src)/include/linux $(LINUXI
ccflags-y += -I$(src)/include
ccflags-y += $(WR_NIC_CFLAGS)
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
ccflags-y += -DWR_NODE
# this is a bad hack. Sometimes we are a submodule, and wr-nic can
......
......@@ -23,20 +23,27 @@
#include "wr-nic.h"
#include "nic-mem.h"
#if WR_IS_NODE
#include "../spec-nic.h"
#endif
/* The remove function is used by probe, so it's not __devexit */
static int wrn_remove(struct platform_device *pdev)
{
#if WR_IS_NODE
struct wrn_drvdata *drvdata = pdev->dev.platform_data;
struct wrn_dev *wrn = drvdata->wrn;
#endif
#if WR_IS_SWITCH
struct wrn_dev *wrn = pdev->dev.platform_data;
#endif
int i;
#if 0
spin_lock(&wrn->lock);
--wrn->use_count; /* Hmmm... looks like overkill... */
spin_unlock(&wrn->lock);
#endif
if (WR_IS_SWITCH) {
spin_lock(&wrn->lock);
--wrn->use_count; /* Hmmm... looks like overkill... */
spin_unlock(&wrn->lock);
}
/* First of all, stop any transmission */
writel(0, &wrn->regs->CR);
......@@ -59,7 +66,6 @@ static int wrn_remove(struct platform_device *pdev)
/* Unregister all interrupts that were registered */
for (i = 0; wrn->irq_registered; i++) {
static int irqs[] = WRN_IRQ_NUMBERS;
if (wrn->irq_registered & (1 << i))
free_irq(irqs[i], wrn);
wrn->irq_registered &= ~(1 << i);
......@@ -73,9 +79,13 @@ static int __wrn_map_resources(struct platform_device *pdev)
int i;
struct resource *res;
void __iomem *ptr;
#if WR_IS_NODE
struct wrn_drvdata *drvdata = pdev->dev.platform_data;
struct wrn_dev *wrn = drvdata->wrn;
#endif
#if WR_IS_SWITCH
struct wrn_dev *wrn = pdev->dev.platform_data;
#endif
/*
* The memory regions are mapped once for all endpoints.
* We don't populate the whole array, but use the resource list
......@@ -86,13 +96,13 @@ static int __wrn_map_resources(struct platform_device *pdev)
continue;
ptr = ioremap(res->start, res->end + 1 - res->start);
if (!ptr) {
dev_err(&pdev->dev, "Remap for res %i (%08lx) failed\n",
i, (long)res->start);
dev_err(&pdev->dev, "Remap for res %i (%pa) failed\n",
i, (void *) res->start);
return -ENOMEM;
}
/* Hack: find the block number and fill the array */
pr_debug("Remapped %08lx (block %i) to %p\n",
(long)res->start, i, ptr);
pr_debug("Remapped %pa (block %i) to %p\n",
(void *) res->start, i, ptr);
wrn->bases[i] = ptr;
}
return 0;
......@@ -102,32 +112,35 @@ static int wrn_probe(struct platform_device *pdev)
{
struct net_device *netdev;
struct wrn_ep *ep;
#if WR_IS_NODE
struct wrn_drvdata *drvdata = pdev->dev.platform_data;
struct wrn_dev *wrn = drvdata->wrn;
#endif
#if WR_IS_SWITCH
struct wrn_dev *wrn = pdev->dev.platform_data;
#endif
int i, err = 0;
#if 0
/* Lazily: irqs are not in the resource list */
static int irqs[] = WRN_IRQ_NUMBERS;
static char *irq_names[] = WRN_IRQ_NAMES;
static irq_handler_t irq_handlers[] = WRN_IRQ_HANDLERS;
#endif
/* No need to lock_irq: we only protect count and continue unlocked */
#if 0
spin_lock(&wrn->lock);
if (++wrn->use_count != 1) {
--wrn->use_count;
if (WR_IS_SWITCH) {
spin_lock(&wrn->lock);
if (++wrn->use_count != 1) {
--wrn->use_count;
spin_unlock(&wrn->lock);
return -EBUSY;
}
spin_unlock(&wrn->lock);
dev_err(&pdev->dev, "use count %i\n", wrn->use_count);
return -EBUSY;
}
spin_unlock(&wrn->lock);
#endif
/* Map our resource list and instantiate the shortcut pointers */
err = __wrn_map_resources(pdev);
if (err)
if ( (err = __wrn_map_resources(pdev)) )
goto out;
wrn->regs = wrn->bases[WRN_FB_NIC];
wrn->txtsu_regs = wrn->bases[WRN_FB_TS];
......@@ -140,16 +153,16 @@ static int wrn_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "regs %p, txd %p, rxd %p, buffer %p\n",
wrn->regs, wrn->txd, wrn->rxd, wrn->databuf);
#if 0
/* Register the interrupt handlers (not shared) */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
err = request_irq(irqs[i], irq_handlers[i],
IRQF_TRIGGER_LOW, irq_names[i], wrn);
if (err)
goto out;
wrn->irq_registered |= 1 << i;
if (WR_IS_SWITCH) {
/* Register the interrupt handlers (not shared) */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
err = request_irq(irqs[i], irq_handlers[i],
IRQF_TRIGGER_LOW, irq_names[i], wrn);
if (err) goto out;
wrn->irq_registered |= 1 << i;
}
}
#endif
/* Reset the device, just to be sure, before making anything */
writel(0, &wrn->regs->CR);
mdelay(10);
......@@ -184,15 +197,14 @@ static int wrn_probe(struct platform_device *pdev)
wrn->dev[i] = netdev;
err = wrn_mezzanine_init(netdev);
if (err)
dev_err(&pdev->dev,
"Init mezzanine code: error %i\n", err);
dev_err(&pdev->dev, "Init mezzanine code: "
"error %i\n", err);
}
if (i == 0)
return -ENODEV; /* no endpoints */
for (i = 0; i < WRN_NR_TXDESC; i++) { /* Clear all tx descriptors */
struct wrn_txd *tx;
tx = wrn->txd + i;
writel(0, &tx->tx1);
}
......@@ -204,7 +216,7 @@ static int wrn_probe(struct platform_device *pdev)
rx = wrn->rxd + i;
offset = __wrn_desc_offset(wrn, WRN_DDIR_RX, i);
writel((2000 << 16) | offset, &rx->rx3);
writel( (2000 << 16) | offset, &rx->rx3);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
}
......
......@@ -16,9 +16,37 @@
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/moduleparam.h>
#include "wr-nic.h"
static char *macaddr = "00:00:00:00:00:00";
module_param(macaddr, charp, 0444);
/* Copied from kernel 3.6 net/utils.c, it converts from MAC string to u8 array */
__weak int mac_pton(const char *s, u8 *mac)
{
int i;
/* XX:XX:XX:XX:XX:XX */
if (strlen(s) < 3 * ETH_ALEN - 1)
return 0;
/* Don't dirty result unless string is valid MAC. */
for (i = 0; i < ETH_ALEN; i++) {
if (!strchr("0123456789abcdefABCDEF", s[i * 3]))
return 0;
if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1]))
return 0;
if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':')
return 0;
}
for (i = 0; i < ETH_ALEN; i++) {
mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]);
}
return 1;
}
/*
* Phy access: used by link status, enable, calibration ioctl etc.
* Called with endpoint lock (you'll lock the whole sequence of r/w)
......@@ -28,7 +56,7 @@ int wrn_phy_read(struct net_device *dev, int phy_id, int location)
struct wrn_ep *ep = netdev_priv(dev);
u32 val;
if (1) {
if (WR_IS_NODE) {
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
......@@ -39,7 +67,7 @@ int wrn_phy_read(struct net_device *dev, int phy_id, int location)
}
wrn_ep_write(ep, MDIO_CR, EP_MDIO_CR_ADDR_W(location));
while ((wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
while( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
val = wrn_ep_read(ep, MDIO_ASR);
/* mask from wbgen macros */
......@@ -51,7 +79,7 @@ void wrn_phy_write(struct net_device *dev, int phy_id, int location,
{
struct wrn_ep *ep = netdev_priv(dev);
if (1) {
if (WR_IS_NODE) {
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
......@@ -65,7 +93,7 @@ void wrn_phy_write(struct net_device *dev, int phy_id, int location,
EP_MDIO_CR_ADDR_W(location)
| EP_MDIO_CR_DATA_W(value)
| EP_MDIO_CR_RW);
while ((wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
while( (wrn_ep_read(ep, MDIO_ASR) & EP_MDIO_ASR_READY) == 0)
;
}
......@@ -83,7 +111,7 @@ static void wrn_update_link_status(struct net_device *dev)
/* Link wnt down? */
if (!mii_link_ok(&ep->mii)) {
if (netif_carrier_ok(dev)) {
if(netif_carrier_ok(dev)) {
netif_carrier_off(dev);
clear_bit(WRN_EP_UP, &ep->ep_flags);
netdev_info(dev, "Link down.\n");
......@@ -93,7 +121,7 @@ static void wrn_update_link_status(struct net_device *dev)
}
/* Currently the link is active */
if (netif_carrier_ok(dev)) {
if(netif_carrier_ok(dev)) {
/* Software already knows it's up */
return;
}
......@@ -110,7 +138,7 @@ static void wrn_update_link_status(struct net_device *dev)
if (0) { /* was commented in minic */
wrn_ep_write(ep, FCR,
EP_FCR_TXPAUSE | EP_FCR_RXPAUSE
EP_FCR_TXPAUSE |EP_FCR_RXPAUSE
| EP_FCR_TX_THR_W(128)
| EP_FCR_TX_QUANTA_W(200));
}
......@@ -126,7 +154,7 @@ static void wrn_update_link_status(struct net_device *dev)
/* reset RMON counters */
ecr = wrn_ep_read(ep, ECR);
wrn_ep_write(ep, ECR, ecr | EP_ECR_RST_CNT);
wrn_ep_write(ep, ECR, ecr);
wrn_ep_write(ep, ECR, ecr );
}
/* Actual timer function. Takes the lock and calls above function */
......@@ -157,8 +185,9 @@ int wrn_ep_open(struct net_device *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
unsigned long timerarg = (unsigned long)dev;
#endif
int prio, prio_map;
if (1) {
if (WR_IS_NODE) {
netif_carrier_on(dev);
return 0; /* No access to EP registers in the SPEC */
}
......@@ -169,12 +198,20 @@ int wrn_ep_open(struct net_device *dev)
| EP_VCR0_PRIO_VAL_W(4), /* some mid priority */
&ep->ep_regs->VCR0);
/* Write default 802.1Q tag priority to traffic class mapping */
prio_map = 0;
for(prio=0; prio<8; ++prio) {
prio_map |= (0x7 & prio) << (prio*3);
}
writel(prio_map, &ep->ep_regs->TCAR);
/*
* enable RX timestamping (it has no impact on performance)
* and we need the RX OOB block to identify orginating endpoints
* for RXed packets -- Tom
*/
writel(EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS, &ep->ep_regs->TSCR);
writel(EP_TSCR_EN_TXTS| EP_TSCR_EN_RXTS, &ep->ep_regs->TSCR);
writel(0
| EP_ECR_PORTID_W(ep->ep_number)
......@@ -189,16 +226,10 @@ int wrn_ep_open(struct net_device *dev)
/* Prepare the timer for link-up notifications */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
setup_timer(&ep->ep_link_timer, wrn_ep_check_link, timerarg);
#else
timer_setup(&ep->ep_link_timer, wrn_ep_check_link, 0);
#endif
if (0) {
/* not on spec */
mod_timer(&ep->ep_link_timer, jiffies + WRN_LINK_POLL_INTERVAL);
} else {
/* Assume it's already on */
netif_carrier_on(dev);
}
/* Not on spec. On spec this part of the function is never reached
* due to return in if(WR_IS_NODE) */
mod_timer(&ep->ep_link_timer, jiffies + WRN_LINK_POLL_INTERVAL);
return 0;
}
......@@ -206,11 +237,11 @@ int wrn_ep_close(struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
if (1)
if (WR_IS_NODE)
return 0; /* No access to EP registers in the SPEC */
/*
* Beware: the system loops in the del_timer_sync below if timer_setup
* had not been called either (see "if (1)" in ep_open above)
* had not been called either (see "if (WR_IS_NODE)" in ep_open above)
*/
writel(0, &ep->ep_regs->ECR);
......@@ -234,10 +265,41 @@ int wrn_endpoint_probe(struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
int epnum, err;
static u8 wraddr[6];
u32 val;
epnum = ep->ep_number;
if(WR_IS_NODE) {
/* If address is not provided as parameter read from lm32 */
if (is_zero_ether_addr(wraddr)) {
/* on the SPEC the lm32 already configured the mac address */
val = readl(&ep->ep_regs->MACH);
put_unaligned_be16(val, wraddr);
val = readl(&ep->ep_regs->MACL);
put_unaligned_be32(val, wraddr+2);
}
}
if(WR_IS_SWITCH) {
/* If the MAC address is 0, then randomize the first MAC */
/* Do not randomize for SPEC */
if (is_zero_ether_addr(wraddr)) {
pr_warn("wr_nic: missing MAC address, randomize\n");
/* randomize a MAC address, so lazy users can avoid ifconfig */
random_ether_addr(wraddr);
/* Clear the MSB on fourth octect to prevent bit overflow on OUI */
wraddr[3] &= 0x7F;
}
}
if (ep->ep_number == 0)
pr_info("WR-nic: Using address %pM\n", wraddr);
/* Use wraddr as MAC */
memcpy(dev->dev_addr, wraddr, ETH_ALEN);
pr_debug("wr_nic: assign MAC %pM to wr%d\n", dev->dev_addr, ep->ep_number);
/* Check whether the ep has been sinthetized or not */
val = readl(&ep->ep_regs->IDCODE);
if (val != WRN_EP_MAGIC) {
......@@ -265,6 +327,11 @@ int wrn_endpoint_probe(struct net_device *dev)
/* Finally, register and succeed, or fail and undo */
err = register_netdev(dev);
/* Increment MAC address for next endpoint */
val = get_unaligned_be32(wraddr + 2);
put_unaligned_be32(val + 1, wraddr + 2);
if (err) {
netdev_err(dev, "Can't register device\n");
__wrn_endpoint_shutdown(ep);
......@@ -272,17 +339,6 @@ int wrn_endpoint_probe(struct net_device *dev)
return err == -ENODEV ? -EIO : err;
}
if (0) {
/* randomize a MAC address, so lazy users can avoid ifconfig */
random_ether_addr(dev->dev_addr);
} else {
/* on the SPEC the lm32 already configured the mac address */
val = readl(&ep->ep_regs->MACH);
put_unaligned_be16(val, dev->dev_addr);
val = readl(&ep->ep_regs->MACL);
put_unaligned_be32(val, dev->dev_addr+2);
}
return 0;
}
......
......@@ -21,6 +21,9 @@
#include <asm/unaligned.h>
#include "wr-nic.h"
#if WR_IS_SWITCH
#include "wr_pstats.h"
#endif
#include "nic-mem.h"
#undef WRN_TRANS_UPDATE
......@@ -72,6 +75,14 @@ static int wrn_open(struct net_device *dev)
if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL;
if(WR_IS_SWITCH) {
/* MACH gets the first two bytes, MACL the rest */
val = get_unaligned_be16(dev->dev_addr);
writel(val, &ep->ep_regs->MACH);
val = get_unaligned_be32(dev->dev_addr+2);
writel(val, &ep->ep_regs->MACL);
}
/* Mark it as down, and start the ep-specific polling timer */
clear_bit(WRN_EP_UP, &ep->ep_flags);
wrn_ep_open(dev);
......@@ -89,7 +100,7 @@ static int wrn_open(struct net_device *dev)
* malformed packets
*/
val = readl(&ep->ep_regs->RFCR) & ~EP_RFCR_MRU_MASK;
writel(val | EP_RFCR_MRU_W(2048), &ep->ep_regs->RFCR);
writel (val | EP_RFCR_MRU_W(2048), &ep->ep_regs->RFCR);
/* Most drivers call platform_set_drvdata() but we don't need it */
return 0;
......@@ -100,8 +111,7 @@ static int wrn_close(struct net_device *dev)
struct wrn_ep *ep = netdev_priv(dev);
int ret;
ret = wrn_ep_close(dev);
if (ret)
if ( (ret = wrn_ep_close(dev)) )
return ret;
/* FIXME: software-only fixing at close time */
......@@ -111,7 +121,7 @@ static int wrn_close(struct net_device *dev)
return 0;
}
static int wrn_set_mac_address(struct net_device *dev, void *vaddr)
static int wrn_set_mac_address(struct net_device *dev, void* vaddr)
{
struct wrn_ep *ep = netdev_priv(dev);
struct sockaddr *addr = vaddr;
......@@ -193,7 +203,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct wrn_ep *ep = netdev_priv(dev);
struct wrn_dev *wrn = ep->wrn;
struct skb_shared_info *info = skb_shinfo(skb);
//unsigned long flags;
unsigned long flags;
int desc;
int id;
int do_stamp = 0;
......@@ -207,13 +217,23 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Allocate a descriptor and id (start from last allocated) */
//spin_lock_irqsave(&wrn->lock, flags);
if(WR_IS_SWITCH){
spin_lock_irqsave(&wrn->lock, flags);
}
desc = __wrn_alloc_tx_desc(wrn);
id = (wrn->id++) & 0xffff;
if (id == 0)
id = wrn->id++; /* 0 cannot be used in the SPEC */
//spin_unlock_irqrestore(&wrn->lock, flags);
if(WR_IS_SWITCH){
spin_unlock_irqrestore(&wrn->lock, flags);
}
if(WR_IS_NODE){
if (id == 0)
id = wrn->id++; /* 0 cannot be used in the SPEC */
}
if (desc < 0) /* error */
return desc;
......@@ -249,13 +269,50 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
#if WR_IS_SWITCH
int (*wr_nic_pstats_callback)(int epnum,
unsigned int ctr[PSTATS_CNT_PP]);
EXPORT_SYMBOL(wr_nic_pstats_callback);
static unsigned int nic_counters[PSTATS_CNT_PP];
static DEFINE_SPINLOCK(nic_counters_lock);
#endif
struct net_device_stats *wrn_get_stats(struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
/* FIXME: we should get the RMON information from endpoint */
#if WR_IS_SWITCH
if (wr_nic_pstats_callback) {
int i;
spin_lock(&nic_counters_lock);
wr_nic_pstats_callback(ep->ep_number, nic_counters);
if (0) {
/* A stupid diagnostics, happens oh so often... */
printk(KERN_INFO "counters for %i:", ep->ep_number);
for (i = 0; i < PSTATS_CNT_PP; i++)
printk(KERN_CONT " %u", nic_counters[i]);
printk(KERN_CONT "\n");
} else {
/* Recover values in the kernel structure */
ep->stats.rx_packets =
nic_counters[PSTATS_C_R_FRAME];
ep->stats.tx_packets =
nic_counters[PSTATS_C_T_FRAME];
ep->stats.rx_length_errors =
nic_counters[PSTATS_C_R_GIANT];
ep->stats.rx_crc_errors =
nic_counters[PSTATS_C_R_CRC_ERROR];
ep->stats.rx_fifo_errors =
nic_counters[PSTATS_C_R_OVERRUN];
ep->stats.tx_fifo_errors =
nic_counters[PSTATS_C_T_UNDERRUN];
}
spin_unlock(&nic_counters_lock);
}
#endif
return &ep->stats;
return NULL;
}
/*
......@@ -275,6 +332,7 @@ int __weak wrn_mezzanine_init(struct net_device *dev)
void __weak wrn_mezzanine_exit(struct net_device *dev)
{
return;
}
......@@ -407,35 +465,42 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
__wrn_copy_in(skb_put(skb, len), wrn->databuf + off, len);
/* Rewrite lenght (modified during rx) and mark it free ASAP */
writel((2000 << 16) | offset, &rx->rx3);
writel( (2000 << 16) | offset, &rx->rx3);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
/* RX timestamping part */
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
if (counter_ppsg < ts_r)
utc--;
if (WR_IS_NODE)
if (counter_ppsg < ts_r)
utc--;
if (WR_IS_SWITCH)
if(counter_ppsg < REFCLK_FREQ/4 && ts_r > 3*REFCLK_FREQ/4)
utc--;
ts.tv_sec = (s32)utc & 0x7fffffff;
cntr_diff = (ts_r & 0xf) - ts_f;
/* the bit says the rising edge cnter is 1tick ahead */
if (cntr_diff == 1 || cntr_diff == (-0xf))
if(cntr_diff == 1 || cntr_diff == (-0xf))
ts.tv_sec |= 0x80000000;
ts.tv_nsec = ts_r * NSEC_PER_TICK;
pr_debug("Timestamp: %li:%li, ahead = %d\n",
ts.tv_sec & 0x7fffffff,
ts.tv_nsec & 0x7fffffff,
ts.tv_sec & 0x80000000 ? 1 : 0);
ts.tv_sec & 0x7fffffff,
ts.tv_nsec & 0x7fffffff,
ts.tv_sec & 0x80000000 ? 1 :0);
if (1) {
if(WR_IS_NODE){
/* SPEC: don't do the strange stuff for wr-ptp */
ts.tv_sec &= ~0x80000000;
ts.tv_nsec &= 0x7fffffff;
}
if (!(r1 & NIC_RX1_D1_TS_INCORRECT)) {
/* If the timestamp was reported as incorrect, pass 0 instead */
if (! (r1 & NIC_RX1_D1_TS_INCORRECT)) /* FIXME: bit name possibly? */
{
hwts = skb_hwtstamps(skb);
hwts->hwtstamp = timespec_to_ktime(ts);
}
......@@ -449,7 +514,7 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
return;
err_out: /* Mark it free anyways -- with its full length */
writel((2000 << 16) | offset, &rx->rx3);
writel( (2000 << 16) | offset, &rx->rx3);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
/* account the error to endpoint 0 -- we don't know who it is */
......@@ -490,7 +555,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
int i;
/* Loop using our tail until one is not sent */
while ((i = wrn->next_tx_tail) != wrn->next_tx_head) {
while ( (i = wrn->next_tx_tail) != wrn->next_tx_head) {
/* Check if this is txdone */
tx = wrn->txd + i;
reg = readl(&tx->tx1);
......
/*
* hardware-specific definitions for the White Rabbit NIC
*
* Copyright (C) 2010-2012 CERN (www.cern.ch)
* Copyright (C) 2010-2014 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -10,7 +10,56 @@
*/
#ifndef __WR_NIC_HARDWARE_H__
#define __WR_NIC_HARDWARE_H__
#if (!defined WR_IS_NODE) && (!defined WR_IS_SWITCH)
#error "WR_NODE and WR_SWITCH not defined!"
#endif
#if WR_IS_SWITCH
/* This is the clock used in internal counters. */
#define REFCLK_FREQ (125000000 / 2)
#define NSEC_PER_TICK (NSEC_PER_SEC / REFCLK_FREQ)
/* The interrupt is one of those managed by our WRVIC device */
#define WRN_IRQ_BASE 192
#define WRN_IRQ_NIC (WRN_IRQ_BASE + 0)
#define WRN_IRQ_TSTAMP (WRN_IRQ_BASE + 1)
//#define WRN_IRQ_PPSG (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTU (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTUT (WRN_IRQ_BASE + )
/*
* V3 Memory map, temporarily (Jan 2012)
*
* 0x00000 - 0x1ffff: RT Subsystem
* 0x00000 - 0x0ffff: RT Subsystem Program Memory (16 - 64 kB)
* 0x10000 - 0x100ff: RT Subsystem UART
* 0x10100 - 0x101ff: RT Subsystem SoftPLL-adv
* 0x10200 - 0x102ff: RT Subsystem SPI Master
* 0x10300 - 0x103ff: RT Subsystem GPIO
* 0x10500 - 0x105ff: PPS gen
* 0x20000 - 0x3ffff: NIC
* 0x20000 - 0x20fff NIC control regs and descriptor area
* 0x28000 - 0x2bfff NIC packet buffer (16k)
* 0x30000 - 0x4ffff: Endpoints
* 0x30000 + N * 0x400 Endpoint N control registers
* 0x50000 - 0x50fff: VIC
* 0x51000 - 0x51fff: Tstamp unit
*/
/* This is the base address of all the FPGA regions (EBI1, CS0) */
#define FPGA_BASE_PPSG 0x10010500
#define FPGA_SIZE_PPSG 0x00000100
#define FPGA_BASE_NIC 0x10020000
#define FPGA_SIZE_NIC 0x00010000
#define FPGA_BASE_EP 0x10030000
#define FPGA_SIZE_EP 0x00010000
#define FPGA_SIZE_EACH_EP 0x400
#define FPGA_BASE_VIC 0x10050000 /* not used here */
#define FPGA_SIZE_VIC 0x00001000
#define FPGA_BASE_TS 0x10051000
#define FPGA_SIZE_TS 0x00001000
#endif /* WR_IS_SWITCH */
#if WR_IS_NODE
/* This is the clock used in internal counters. */
#define REFCLK_FREQ (125000000)
#define NSEC_PER_TICK (NSEC_PER_SEC / REFCLK_FREQ)
......@@ -70,6 +119,8 @@
#define FPGA_SIZE_VIC 0x00000100
#define FPGA_BASE_TS 0x00061000
#define FPGA_SIZE_TS 0x0000 100
#endif /* ifdef WR_IS_NODE */
enum fpga_blocks {
WRN_FB_NIC,
......@@ -80,14 +131,19 @@ enum fpga_blocks {
};
/* In addition to the above enumeration, we scan for those many endpoints */
#define WRN_NR_ENDPOINTS 1
#if WR_IS_NODE
# define WRN_NR_ENDPOINTS 1
#endif
#if WR_IS_SWITCH
# define WRN_NR_ENDPOINTS 18
#endif
/* 8 tx and 8 rx descriptors */
#define WRN_NR_DESC 8
#define WRN_NR_TXDESC WRN_NR_DESC
#define WRN_NR_RXDESC WRN_NR_DESC
/* Magic number for endpoint (missing, I fear) */
/* Magic number for endpoint */
#define WRN_EP_MAGIC 0xcafebabe
/*
......
......@@ -25,6 +25,17 @@
#ifdef __KERNEL__ /* The rest is kernel-only */
/* The NIC can build for both the switch and the node. Prefer if to ifdef */
#if defined WR_NODE
# define WR_IS_NODE 1
# define WR_IS_SWITCH 0
#elif defined WR_SWITCH
# define WR_IS_NODE 0
# define WR_IS_SWITCH 1
#else
# error "Please define WR_NODE or WR_SWITCH"
#endif
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mii.h> /* Needed for stuct mii_if_info in wrn_dev */
......@@ -33,7 +44,6 @@
#include "nic-hardware.h" /* Magic numbers: please fix them as needed */
#define DRV_NAME "wr-nic" /* Used in messages and device/driver names */
#define DRV_VERSION "0.1" /* For ethtool->get_drvinfo -- FIXME: auto-vers */
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment