void cxgb_offload_deactivate(struct adapter *adapter) { struct t3cdev *tdev = &adapter->tdev; struct t3c_data *t = T3C_DATA(tdev); printf("removing adapter %p\n", adapter); remove_adapter(adapter); if (TAILQ_EMPTY(&adapter_list)) { #if defined(CONFIG_CHELSIO_T3_MODULE) restore_arp_sans_t3core(); #endif } free_tid_maps(&t->tid_maps); T3C_DATA(tdev) = NULL; t3_free_l2t(L2DATA(tdev)); L2DATA(tdev) = NULL; mtx_destroy(&t->tid_release_lock); free(t, M_CXGB); }
struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, struct net_device *dev) { struct l2t_entry *e; struct l2t_data *d = L2DATA(cdev); u32 addr = *(u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; int hash = arp_hash(addr, ifidx, d); struct port_info *p = netdev_priv(dev); int smt_idx = p->port_id; write_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) if (e->addr == addr && e->ifindex == ifidx && e->smt_idx == smt_idx) { l2t_hold(d, e); if (atomic_read(&e->refcnt) == 1) reuse_entry(e, neigh); goto done; } /* Need to allocate a new entry */ e = alloc_l2e(d); if (e) { spin_lock(&e->lock); /* avoid race with t3_l2t_free */ e->next = d->l2tab[hash].first; d->l2tab[hash].first = e; e->state = L2T_STATE_RESOLVING; e->addr = addr; e->ifindex = ifidx; e->smt_idx = smt_idx; atomic_set(&e->refcnt, 1); neigh_replace(e, neigh); if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) e->vlan = vlan_dev_vlan_id(neigh->dev); else e->vlan = VLAN_NONE; spin_unlock(&e->lock); } done: write_unlock_bh(&d->lock); return e; }
/* * Called when the host's ARP layer makes a change to some entry that is * loaded into the HW L2 table. */ void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) { struct l2t_entry *e; struct sk_buff *arpq = NULL; struct l2t_data *d = L2DATA(dev); u32 addr = *(u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; int hash = arp_hash(addr, ifidx, d); read_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) if (e->addr == addr && e->ifindex == ifidx) { spin_lock(&e->lock); goto found; } read_unlock_bh(&d->lock); return; found: read_unlock(&d->lock); if (atomic_read(&e->refcnt)) { if (neigh != e->neigh) neigh_replace(e, neigh); if (e->state == L2T_STATE_RESOLVING) { if (neigh->nud_state & NUD_FAILED) { arpq = e->arpq_head; e->arpq_head = e->arpq_tail = NULL; } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) setup_l2e_send_pending(dev, NULL, e); } else { e->state = neigh->nud_state & NUD_CONNECTED ? L2T_STATE_VALID : L2T_STATE_STALE; if (memcmp(e->dmac, neigh->ha, 6)) setup_l2e_send_pending(dev, NULL, e); } } spin_unlock_bh(&e->lock); if (arpq) handle_failed_resolution(dev, arpq); }
int cxgb_offload_activate(struct adapter *adapter) { struct t3cdev *dev = &adapter->tdev; int natids, err; struct t3c_data *t; struct tid_range stid_range, tid_range; struct mtutab mtutab; unsigned int l2t_capacity; t = malloc(sizeof(*t), M_CXGB, M_NOWAIT|M_ZERO); if (!t) return (ENOMEM); dev->adapter = adapter; err = (EOPNOTSUPP); if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || dev->ctl(dev, GET_MTUS, &mtutab) < 0 || dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) { device_printf(adapter->dev, "%s: dev->ctl check failed\n", __FUNCTION__); goto out_free; } err = (ENOMEM); L2DATA(dev) = t3_init_l2t(l2t_capacity); if (!L2DATA(dev)) { device_printf(adapter->dev, "%s: t3_init_l2t failed\n", __FUNCTION__); goto out_free; } natids = min(tid_range.num / 2, MAX_ATIDS); err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, stid_range.num, ATID_BASE, stid_range.base); if (err) { device_printf(adapter->dev, "%s: init_tid_tabs failed\n", __FUNCTION__); goto out_free_l2t; } t->mtus = mtutab.mtus; t->nmtus = mtutab.size; TASK_INIT(&t->tid_release_task, 0 /* XXX? */, t3_process_tid_release_list, dev); mtx_init(&t->tid_release_lock, "tid release", NULL, MTX_DUPOK|MTX_DEF); t->dev = dev; T3C_DATA (dev) = t; dev->recv = process_rx; dev->arp_update = t3_l2t_update; /* Register netevent handler once */ if (TAILQ_EMPTY(&adapter_list)) { #if defined(CONFIG_CHELSIO_T3_MODULE) if (prepare_arp_with_t3core()) log(LOG_ERR, "Unable to set offload capabilities\n"); #endif } CTR1(KTR_CXGB, "adding adapter %p", adapter); add_adapter(adapter); device_printf(adapter->dev, "offload started\n"); adapter->flags |= CXGB_OFLD_INIT; return (0); out_free_l2t: t3_free_l2t(L2DATA(dev)); L2DATA(dev) = NULL; out_free: free(t, M_CXGB); return (err); }