Commit e09e5b30 authored by Miguel Jimenez Lopez's avatar Miguel Jimenez Lopez

Changes for IRQ registering using a special IORESOURCE_BUS resource from parent driver.

parent 14c688f0
/*
* Device initialization and cleanup for White-Rabbit switch network interface
*
* Copyright (C) 2019 Seven Solutions (sevensols.com)
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Partly from previous work by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
......@@ -30,15 +33,30 @@
* a module parameter or somehow configurable. For the time being we keep
* it hard-coded here.
*/
#if WR_IS_SWITCH
static const char *irqdomain_name = "htvic-wr-swi.0";
#else
static const char *irqdomain_name = "htvic-spec.0";
#endif
#define HTVIC_IRQDOMAIN_NAME "htvic-irq"
static struct irq_domain * irq_find_irqdomain(const char *name)
{
struct irq_fwspec fwspec;
struct irq_domain *d = NULL;
memset(&fwspec,0,sizeof(fwspec));
fwspec.fwnode = (struct fwnode_handle *) name;
fwspec.param_count = 1;
d = irq_find_matching_fwspec(&fwspec,DOMAIN_BUS_ANY);
return d;
}
static inline struct wrn_dev *wrn_from_pdev(struct platform_device *pdev)
{
#if WR_IS_SWITCH
return pdev->dev.platform_data;
#else
return &wrn_dev;
#endif
}
/* The remove function is used by probe, so it's not __devexit */
......@@ -47,14 +65,25 @@ static int wrn_remove(struct platform_device *pdev)
struct wrn_dev *wrn = wrn_from_pdev(pdev);
int i, irq;
struct irq_domain *irqdomain;
char *irqdomain_name;
struct resource *r;
r = platform_get_resource(pdev, IORESOURCE_BUS, 0);
irqdomain = irq_find_host((struct device_node *)irqdomain_name);
irqdomain_name = kasprintf(GFP_KERNEL, "%s-%d:%d",
HTVIC_IRQDOMAIN_NAME,
(unsigned char) ((!r) ? 0 : r->start),
(unsigned int) ((!r) ? 0 : r->end));
irqdomain = irq_find_irqdomain(irqdomain_name);
if (!irqdomain) {
dev_err(&pdev->dev, "The IRQ domain %s does not exist\n",
irqdomain_name);
return -EINVAL;
}
kfree(irqdomain_name);
if (WR_IS_SWITCH) {
spin_lock(&wrn->lock);
--wrn->use_count; /* Hmmm... looks like overkill... */
......@@ -79,6 +108,7 @@ static int wrn_remove(struct platform_device *pdev)
iounmap(wrn->bases[i]);
}
if (WR_IS_SWITCH) {
/* Unregister all interrupts that were registered */
for (i = 0; wrn->irq_registered; i++) {
static int irqs[] = WRN_IRQ_NUMBERS;
......@@ -88,6 +118,18 @@ static int wrn_remove(struct platform_device *pdev)
}
wrn->irq_registered &= ~(1 << i);
}
} else {
struct resource *res;
for (i = 0; i < pdev->num_resources; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res)
continue;
irq = irq_find_mapping(irqdomain, res->start);
free_irq(irq, wrn);
wrn->irq_registered &= ~(1 << i);
}
}
return 0;
}
......@@ -107,6 +149,7 @@ static int __wrn_map_resources(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res || !res->start)
continue;
ptr = ioremap(res->start, res->end + 1 - res->start);
if (!ptr) {
dev_err(&pdev->dev, "Remap for res %i %pr failed\n",
......@@ -138,9 +181,9 @@ static int __wrn_map_irq(struct platform_device *pdev, struct irq_domain *irqdom
/* Register the interrupt handlers (not shared) */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
irq = irq_find_mapping(irqdomain, irqs[i]);
err = request_irq(irq, irq_handlers[i],
err = request_any_context_irq(irq, irq_handlers[i],
IRQF_TRIGGER_LOW, irq_names[i], wrn);
if (err)
if (err < 0)
break;
wrn->irq_registered |= 1 << i;
}
......@@ -151,15 +194,18 @@ static int __wrn_map_irq(struct platform_device *pdev, struct irq_domain *irqdom
if (!res)
continue;
irq = irq_find_mapping(irqdomain, res->start);
err = request_irq(irq, irq_handlers[i],
IRQF_TRIGGER_LOW, res->name, wrn);
if (err)
err = request_any_context_irq(irq, irq_handlers[i],
IRQF_TRIGGER_HIGH, res->name, wrn);
if (err < 0) {
printk("%s: request_irq error %d \n",__func__,err);
break;
}
wrn->irq_registered |= 1 << i;
}
}
return err;
return (err < 0) ? err : 0;
}
static int wrn_probe(struct platform_device *pdev)
......@@ -169,14 +215,25 @@ static int wrn_probe(struct platform_device *pdev)
struct wrn_dev *wrn = wrn_from_pdev(pdev);
int i, err = 0;
struct irq_domain *irqdomain;
char *irqdomain_name;
struct resource *r;
r = platform_get_resource(pdev, IORESOURCE_BUS, 0);
irqdomain_name = kasprintf(GFP_KERNEL, "%s-%d:%d",
HTVIC_IRQDOMAIN_NAME,
(unsigned char) ((!r) ? 0 : r->start),
(unsigned int) ((!r) ? 0 : r->end));
irqdomain = irq_find_host((struct device_node *)irqdomain_name);
irqdomain = irq_find_irqdomain(irqdomain_name);
if (!irqdomain) {
dev_err(&pdev->dev, "The IRQ domain %s does not exist\n",
irqdomain_name);
return -EINVAL;
}
kfree(irqdomain_name);
/* No need to lock_irq: we only protect count and continue unlocked */
if (WR_IS_SWITCH) {
spin_lock(&wrn->lock);
......@@ -191,6 +248,7 @@ static int wrn_probe(struct platform_device *pdev)
/* Map our resource list and instantiate the shortcut pointers */
if ( (err = __wrn_map_resources(pdev)) )
goto out;
wrn->regs = wrn->bases[WRN_FB_NIC];
wrn->txtsu_regs = wrn->bases[WRN_FB_TS];
wrn->ppsg_regs = wrn->bases[WRN_FB_PPSG];
......@@ -198,10 +256,7 @@ static int wrn_probe(struct platform_device *pdev)
wrn->rxd = ((void *)wrn->regs) + 0x100; /* was: RX1_D1 */
wrn->databuf = (void *)wrn->regs + NIC_MEM_BASE;
tasklet_init(&wrn->rx_tlet, wrn_rx_interrupt, (unsigned long)wrn);
if (0)
printk("regs %p, txd %p, rxd %p, buffer %p\n",
wrn->regs, wrn->txd, wrn->rxd, wrn->databuf);
;
/* Map our interrupts */
if( (err = __wrn_map_irq(pdev,irqdomain)) )
goto out;
......@@ -216,15 +271,12 @@ static int wrn_probe(struct platform_device *pdev)
err = -ENOMEM;
goto out;
}
/* The ep structure is filled before calling ep_probe */
ep = netdev_priv(netdev);
ep->wrn = wrn;
ep->ep_regs = wrn->bases[WRN_FB_EP] + i * FPGA_SIZE_EACH_EP;
ep->ep_number = i;
#if 0 /* FIXME: UPlink or not? */
if (i < WRN_NR_UPLINK)
set_bit(WRN_EP_IS_UPLINK, &ep->ep_flags);
#endif
/* The netdevice thing is registered from the endpoint */
err = wrn_endpoint_probe(netdev);
......@@ -232,6 +284,7 @@ static int wrn_probe(struct platform_device *pdev)
break;
if (err)
goto out;
/* This endpoint went in properly */
wrn->dev[i] = netdev;
err = wrn_mezzanine_init(netdev);
......@@ -258,7 +311,6 @@ static int wrn_probe(struct platform_device *pdev)
writel( (2000 << 16) | offset, &rx->rx3);
writel(NIC_RX1_D1_EMPTY, &rx->rx1);
}
/*
* make sure all head/tail are 0 -- not needed here, but if we
* disable and then re-enable, this _is_ needed
......@@ -277,6 +329,7 @@ out:
} else {
dev_info(&pdev->dev, "White Rabbit NIC driver\n");
}
return err;
}
......
......@@ -110,15 +110,11 @@ static void wrn_update_link_status(struct net_device *dev)
bmsr = wrn_phy_read(dev, 0, MII_BMSR);
bmcr = wrn_phy_read(dev, 0, MII_BMCR);
//netdev_dbg(dev, "%s: read %x %x", __func__, bmsr, bmcr);
// printk("%s: read %x %x %x\n", __func__, bmsr, bmcr);
/* Link wnt down? */
if (!mii_link_ok(&ep->mii)) {
if(netif_carrier_ok(dev)) {
netif_carrier_off(dev);
clear_bit(WRN_EP_UP, &ep->ep_flags);
printk(KERN_INFO "%s: Link down.\n", dev->name);
return;
}
return;
......@@ -147,8 +143,6 @@ static void wrn_update_link_status(struct net_device *dev)
| EP_FCR_TX_QUANTA_W(200));
}
printk(KERN_INFO "%s: Link up, lpa 0x%04x.\n",
dev->name, lpa);
} else {
/* No autonegotiation. It's up immediately */
printk(KERN_INFO "%s: Link up.\n", dev->name);
......
......@@ -19,9 +19,12 @@
#include "wr-nic.h"
#if WR_IS_SWITCH
/* Our platform data is actually the device itself, and we have 1 only */
static struct wrn_dev wrn_dev;
#else
struct wrn_dev wrn_dev;
#endif
#if WR_IS_SWITCH
/* The WRN_RES_ names are defined in the header file. Each block 64kB */
......
......@@ -66,7 +66,6 @@ static int wrn_open(struct net_device *dev)
u32 val;
/* This is "open" just for an endpoint. The nic hw is already on */
//netdev_dbg(dev, "%s\n", __func__);
if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL;
......@@ -124,10 +123,7 @@ static int wrn_set_mac_address(struct net_device *dev, void* vaddr)
struct sockaddr *addr = vaddr;
u32 val;
//netdev_dbg(dev, "%s\n", __func__);
if (!is_valid_ether_addr(addr->sa_data)) {
//netdev_dbg(dev, "%s: invalid\n", __func__);
return -EADDRNOTAVAIL;
}
......@@ -181,8 +177,6 @@ static void __wrn_tx_desc(struct wrn_ep *ep, int desc,
__wrn_copy_out(ptr, data, len);
/* TX register 3: mask of endpoints (FIXME: broadcast) */
//printk("EP Num: %d\n", ep->ep_number);
writel(1<<ep->ep_number, &tx->tx3);
/* TX register 2: offset and length */
......@@ -227,8 +221,6 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
data = skb->data;
len = skb->len;
//spin_lock_irqsave(&ep->lock, flags);
if (wrn->skb_desc[desc].skb) {
pr_warn("%s: discarding tx frame that got no timestamp\n",
__func__);
......@@ -237,8 +229,6 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
wrn->skb_desc[desc].skb = skb; /* Save for tx irq and stamping */
wrn->skb_desc[desc].frame_id = id; /* Save for tx irq and stamping */
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
/* FIXME: check the WRN_EP_STAMPING_TX flag and its meaning */
if (info->tx_flags & SKBTX_HW_TSTAMP) {
/* hardware timestamping is enabled */
......@@ -253,7 +243,6 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
ep->stats.tx_bytes += len;
trans_update(dev);
//spin_unlock_irqrestore(&ep->lock, flags);
return 0;
}
......@@ -356,12 +345,6 @@ static const struct net_device_ops wrn_netdev_ops = {
.ndo_get_stats = wrn_get_stats,
.ndo_set_mac_address = wrn_set_mac_address,
.ndo_do_ioctl = wrn_ioctl,
#if 0
/* Missing ops, possibly to add later */
.ndo_set_multicast_list = wrn_set_multicast_list,
.ndo_change_mtu = wrn_change_mtu,
/* There are several more, but not really useful for us */
#endif
};
......@@ -575,5 +558,6 @@ irqreturn_t wrn_interrupt(int irq, void *dev_id)
writel(NIC_EIC_ISR_RCOMP, (void *)regs + 0x2c);
tasklet_schedule(&wrn->rx_tlet);
}
return IRQ_HANDLED;
}
......@@ -23,9 +23,6 @@
#define WRN_IRQ_BASE 0
#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)
......@@ -68,9 +65,6 @@
#define WRN_IRQ_BASE 0 /* FIXME: relative to pci dev */
#define WRN_IRQ_NIC (WRN_IRQ_BASE + 0)
#define WRN_IRQ_TSTAMP /* (WRN_IRQ_BASE + 1) -- not used here */
//#define WRN_IRQ_PPSG (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTU (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTUT (WRN_IRQ_BASE + )
/*
* spec-wr-nic memory map (from SDB dump):
......
......@@ -98,7 +98,6 @@ irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
struct TXTSU_WB *regs = wrn->txtsu_regs;
u32 r0, r1, r2;
/* printk("%s: %i\n", __func__, __LINE__); */
/* FIXME: locking */
r0 = readl(&regs->TSF_R0);
r1 = readl(&regs->TSF_R1);
......@@ -106,6 +105,7 @@ irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
record_tstamp(wrn, r0, r1, r2);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_ISR); /* ack irq */
return IRQ_HANDLED;
}
......
......@@ -106,14 +106,6 @@ struct wrn_dev {
struct net_device *dev[WRN_NR_ENDPOINTS];
/* FIXME: all dev fields must be verified */
//unsigned int rx_head, rx_avail, rx_base, rx_size;
//unsigned int tx_head, tx_avail, tx_base, tx_size;
//u32 cur_rx_desc;
int use_count; /* only used at probe time */
int irq_registered;
};
......@@ -135,12 +127,6 @@ struct wrn_ep {
int pkt_count; /* used for tx stamping ID */
struct net_device_stats stats;
//struct sk_buff *current_skb;
//bool synced;
//bool syncing_counters;
//u32 cur_rx_desc;
};
#define WRN_LINK_POLL_INTERVAL (HZ/5)
......@@ -216,6 +202,9 @@ struct wrn_phase_req {
#define WRN_MDIO_WR_SPEC_RX_CAL_STAT 0x02 /* RX calib status */
#define WRN_MDIO_WR_SPEC_CAL_CRST 0x04 /* Reset calibration counter */
#if WR_IS_NODE
extern struct wrn_dev wrn_dev;
#endif
/* Following functions are in nic-core.c */
extern irqreturn_t wrn_interrupt(int irq, void *dev_id);
......
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