This patch adds code to support multiple interrupt vectors around the
kernel's interrupt API.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
static void tg3_irq_quiesce(struct tg3 *tp)
{
static void tg3_irq_quiesce(struct tg3 *tp)
{
BUG_ON(tp->irq_sync);
tp->irq_sync = 1;
smp_mb();
BUG_ON(tp->irq_sync);
tp->irq_sync = 1;
smp_mb();
- synchronize_irq(tp->pdev->irq);
+ for (i = 0; i < tp->irq_cnt; i++)
+ synchronize_irq(tp->napi[i].irq_vec);
}
static inline int tg3_irq_sync(struct tg3 *tp)
}
static inline int tg3_irq_sync(struct tg3 *tp)
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
{
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
struct tg3 *tp = netdev_priv(dev);
- tg3_interrupt(tp->pdev->irq, dev);
+ for (i = 0; i < tp->irq_cnt; i++)
+ tg3_interrupt(tp->napi[i].irq_vec, dev);
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
tp->napi[0].last_tag = 0;
tp->napi[0].last_irq_tag = 0;
smp_mb();
tp->napi[0].last_tag = 0;
tp->napi[0].last_irq_tag = 0;
smp_mb();
- synchronize_irq(tp->pdev->irq);
+
+ for (i = 0; i < tp->irq_cnt; i++)
+ synchronize_irq(tp->napi[i].irq_vec);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
-static int tg3_request_irq(struct tg3 *tp)
+static int tg3_request_irq(struct tg3 *tp, int irq_num)
{
irq_handler_t fn;
unsigned long flags;
{
irq_handler_t fn;
unsigned long flags;
- char *name = tp->dev->name;
+ char *name;
+ struct tg3_napi *tnapi = &tp->napi[irq_num];
+
+ if (tp->irq_cnt == 1)
+ name = tp->dev->name;
+ else {
+ name = &tnapi->irq_lbl[0];
+ snprintf(name, IFNAMSIZ, "%s-%d", tp->dev->name, irq_num);
+ name[IFNAMSIZ-1] = 0;
+ }
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
fn = tg3_msi;
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
fn = tg3_msi;
fn = tg3_interrupt_tagged;
flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
}
fn = tg3_interrupt_tagged;
flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
}
- return request_irq(tp->pdev->irq, fn, flags, name, &tp->napi[0]);
+
+ return request_irq(tnapi->irq_vec, fn, flags, name, tnapi);
}
static int tg3_test_interrupt(struct tg3 *tp)
}
static int tg3_test_interrupt(struct tg3 *tp)
- free_irq(tp->pdev->irq, tnapi);
+ free_irq(tnapi->irq_vec, tnapi);
- err = request_irq(tp->pdev->irq, tg3_test_isr,
+ err = request_irq(tnapi->irq_vec, tg3_test_isr,
IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi);
if (err)
return err;
IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi);
if (err)
return err;
- free_irq(tp->pdev->irq, tnapi);
+ free_irq(tnapi->irq_vec, tnapi);
- err = tg3_request_irq(tp);
+ err = tg3_request_irq(tp, 0);
"the PCI maintainer and include system chipset information.\n",
tp->dev->name);
"the PCI maintainer and include system chipset information.\n",
tp->dev->name);
- free_irq(tp->pdev->irq, &tp->napi[0]);
+ free_irq(tp->napi[0].irq_vec, &tp->napi[0]);
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
- err = tg3_request_irq(tp);
+ err = tg3_request_irq(tp, 0);
tg3_full_unlock(tp);
if (err)
tg3_full_unlock(tp);
if (err)
- free_irq(tp->pdev->irq, &tp->napi[0]);
+ free_irq(tp->napi[0].irq_vec, &tp->napi[0]);
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
}
}
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
}
}
+
+ tp->irq_cnt = 1;
+ tp->napi[0].irq_vec = tp->pdev->irq;
}
static void tg3_ints_fini(struct tg3 *tp)
}
static void tg3_ints_fini(struct tg3 *tp)
static int tg3_open(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
static int tg3_open(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
if (tp->fw_needed) {
err = tg3_request_firmware(tp);
if (tp->fw_needed) {
err = tg3_request_firmware(tp);
napi_enable(&tp->napi[0].napi);
napi_enable(&tp->napi[0].napi);
- err = tg3_request_irq(tp);
+ for (i = 0; i < tp->irq_cnt; i++) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+ err = tg3_request_irq(tp, i);
+ if (err) {
+ for (i--; i >= 0; i--)
+ free_irq(tnapi->irq_vec, tnapi);
+ break;
+ }
+ }
- free_irq(tp->pdev->irq, &tp->napi[0]);
+ for (i = tp->irq_cnt - 1; i >= 0; i--) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+ free_irq(tnapi->irq_vec, tnapi);
+ }
err_out1:
napi_disable(&tp->napi[0].napi);
err_out1:
napi_disable(&tp->napi[0].napi);
static int tg3_close(struct net_device *dev)
{
static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
napi_disable(&tp->napi[0].napi);
struct tg3 *tp = netdev_priv(dev);
napi_disable(&tp->napi[0].napi);
- free_irq(tp->pdev->irq, &tp->napi[0]);
+ for (i = tp->irq_cnt - 1; i >= 0; i--) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+ free_irq(tnapi->irq_vec, tnapi);
+ }
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE;
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE;
dma_addr_t status_mapping;
dma_addr_t rx_rcb_mapping;
dma_addr_t tx_desc_mapping;
dma_addr_t status_mapping;
dma_addr_t rx_rcb_mapping;
dma_addr_t tx_desc_mapping;
+
+ char irq_lbl[IFNAMSIZ];
+ unsigned int irq_vec;
#define SST_25VF0X0_PAGE_SIZE 4098
#define SST_25VF0X0_PAGE_SIZE 4098
+ unsigned int irq_max;
+ unsigned int irq_cnt;
+
struct ethtool_coalesce coal;
/* firmware info */
struct ethtool_coalesce coal;
/* firmware info */