cxgb4: Replace arpq_head/arpq_tail with SKB double link-list code
Based on original work by Michael Werner <werner@chelsio.com> Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9baeb9d7d8
commit
749cb5fe48
@ -174,15 +174,11 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync)
|
|||||||
*/
|
*/
|
||||||
static void send_pending(struct adapter *adap, struct l2t_entry *e)
|
static void send_pending(struct adapter *adap, struct l2t_entry *e)
|
||||||
{
|
{
|
||||||
while (e->arpq_head) {
|
struct sk_buff *skb;
|
||||||
struct sk_buff *skb = e->arpq_head;
|
|
||||||
|
|
||||||
e->arpq_head = skb->next;
|
while ((skb = __skb_dequeue(&e->arpq)) != NULL)
|
||||||
skb->next = NULL;
|
|
||||||
t4_ofld_send(adap, skb);
|
t4_ofld_send(adap, skb);
|
||||||
}
|
}
|
||||||
e->arpq_tail = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process a CPL_L2T_WRITE_RPL. Wake up the ARP queue if it completes a
|
* Process a CPL_L2T_WRITE_RPL. Wake up the ARP queue if it completes a
|
||||||
@ -221,12 +217,7 @@ void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl)
|
|||||||
*/
|
*/
|
||||||
static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
|
static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
skb->next = NULL;
|
__skb_queue_tail(&e->arpq, skb);
|
||||||
if (e->arpq_head)
|
|
||||||
e->arpq_tail->next = skb;
|
|
||||||
else
|
|
||||||
e->arpq_head = skb;
|
|
||||||
e->arpq_tail = skb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb,
|
int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb,
|
||||||
@ -258,7 +249,8 @@ again:
|
|||||||
if (e->state == L2T_STATE_RESOLVING &&
|
if (e->state == L2T_STATE_RESOLVING &&
|
||||||
!neigh_event_send(e->neigh, NULL)) {
|
!neigh_event_send(e->neigh, NULL)) {
|
||||||
spin_lock_bh(&e->lock);
|
spin_lock_bh(&e->lock);
|
||||||
if (e->state == L2T_STATE_RESOLVING && e->arpq_head)
|
if (e->state == L2T_STATE_RESOLVING &&
|
||||||
|
!skb_queue_empty(&e->arpq))
|
||||||
write_l2e(adap, e, 1);
|
write_l2e(adap, e, 1);
|
||||||
spin_unlock_bh(&e->lock);
|
spin_unlock_bh(&e->lock);
|
||||||
}
|
}
|
||||||
@ -360,20 +352,16 @@ exists:
|
|||||||
static void _t4_l2e_free(struct l2t_entry *e)
|
static void _t4_l2e_free(struct l2t_entry *e)
|
||||||
{
|
{
|
||||||
struct l2t_data *d;
|
struct l2t_data *d;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
|
if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
|
||||||
if (e->neigh) {
|
if (e->neigh) {
|
||||||
neigh_release(e->neigh);
|
neigh_release(e->neigh);
|
||||||
e->neigh = NULL;
|
e->neigh = NULL;
|
||||||
}
|
}
|
||||||
while (e->arpq_head) {
|
while ((skb = __skb_dequeue(&e->arpq)) != NULL)
|
||||||
struct sk_buff *skb = e->arpq_head;
|
|
||||||
|
|
||||||
e->arpq_head = skb->next;
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
e->arpq_tail = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
d = container_of(e, struct l2t_data, l2tab[e->idx]);
|
d = container_of(e, struct l2t_data, l2tab[e->idx]);
|
||||||
atomic_inc(&d->nfree);
|
atomic_inc(&d->nfree);
|
||||||
@ -383,6 +371,7 @@ static void _t4_l2e_free(struct l2t_entry *e)
|
|||||||
static void t4_l2e_free(struct l2t_entry *e)
|
static void t4_l2e_free(struct l2t_entry *e)
|
||||||
{
|
{
|
||||||
struct l2t_data *d;
|
struct l2t_data *d;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
spin_lock_bh(&e->lock);
|
spin_lock_bh(&e->lock);
|
||||||
if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
|
if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
|
||||||
@ -390,14 +379,9 @@ static void t4_l2e_free(struct l2t_entry *e)
|
|||||||
neigh_release(e->neigh);
|
neigh_release(e->neigh);
|
||||||
e->neigh = NULL;
|
e->neigh = NULL;
|
||||||
}
|
}
|
||||||
while (e->arpq_head) {
|
while ((skb = __skb_dequeue(&e->arpq)) != NULL)
|
||||||
struct sk_buff *skb = e->arpq_head;
|
|
||||||
|
|
||||||
e->arpq_head = skb->next;
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
e->arpq_tail = NULL;
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&e->lock);
|
spin_unlock_bh(&e->lock);
|
||||||
|
|
||||||
d = container_of(e, struct l2t_data, l2tab[e->idx]);
|
d = container_of(e, struct l2t_data, l2tab[e->idx]);
|
||||||
@ -529,18 +513,19 @@ EXPORT_SYMBOL(cxgb4_select_ntuple);
|
|||||||
* on the arpq head. If a packet specifies a failure handler it is invoked,
|
* on the arpq head. If a packet specifies a failure handler it is invoked,
|
||||||
* otherwise the packet is sent to the device.
|
* otherwise the packet is sent to the device.
|
||||||
*/
|
*/
|
||||||
static void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq)
|
static void handle_failed_resolution(struct adapter *adap, struct l2t_entry *e)
|
||||||
{
|
{
|
||||||
while (arpq) {
|
struct sk_buff *skb;
|
||||||
struct sk_buff *skb = arpq;
|
|
||||||
|
while ((skb = __skb_dequeue(&e->arpq)) != NULL) {
|
||||||
const struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
|
const struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
|
||||||
|
|
||||||
arpq = skb->next;
|
spin_unlock(&e->lock);
|
||||||
skb->next = NULL;
|
|
||||||
if (cb->arp_err_handler)
|
if (cb->arp_err_handler)
|
||||||
cb->arp_err_handler(cb->handle, skb);
|
cb->arp_err_handler(cb->handle, skb);
|
||||||
else
|
else
|
||||||
t4_ofld_send(adap, skb);
|
t4_ofld_send(adap, skb);
|
||||||
|
spin_lock(&e->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +536,7 @@ static void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq)
|
|||||||
void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
|
void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
|
||||||
{
|
{
|
||||||
struct l2t_entry *e;
|
struct l2t_entry *e;
|
||||||
struct sk_buff *arpq = NULL;
|
struct sk_buff_head *arpq = NULL;
|
||||||
struct l2t_data *d = adap->l2t;
|
struct l2t_data *d = adap->l2t;
|
||||||
int addr_len = neigh->tbl->key_len;
|
int addr_len = neigh->tbl->key_len;
|
||||||
u32 *addr = (u32 *) neigh->primary_key;
|
u32 *addr = (u32 *) neigh->primary_key;
|
||||||
@ -578,10 +563,9 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
|
|||||||
|
|
||||||
if (e->state == L2T_STATE_RESOLVING) {
|
if (e->state == L2T_STATE_RESOLVING) {
|
||||||
if (neigh->nud_state & NUD_FAILED) {
|
if (neigh->nud_state & NUD_FAILED) {
|
||||||
arpq = e->arpq_head;
|
arpq = &e->arpq;
|
||||||
e->arpq_head = e->arpq_tail = NULL;
|
|
||||||
} else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) &&
|
} else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) &&
|
||||||
e->arpq_head) {
|
!skb_queue_empty(&e->arpq)) {
|
||||||
write_l2e(adap, e, 1);
|
write_l2e(adap, e, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -591,10 +575,9 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
|
|||||||
write_l2e(adap, e, 0);
|
write_l2e(adap, e, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_bh(&e->lock);
|
|
||||||
|
|
||||||
if (arpq)
|
if (arpq)
|
||||||
handle_failed_resolution(adap, arpq);
|
handle_failed_resolution(adap, e);
|
||||||
|
spin_unlock_bh(&e->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate an L2T entry for use by a switching rule. Such need to be
|
/* Allocate an L2T entry for use by a switching rule. Such need to be
|
||||||
@ -681,6 +664,7 @@ struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end)
|
|||||||
d->l2tab[i].state = L2T_STATE_UNUSED;
|
d->l2tab[i].state = L2T_STATE_UNUSED;
|
||||||
spin_lock_init(&d->l2tab[i].lock);
|
spin_lock_init(&d->l2tab[i].lock);
|
||||||
atomic_set(&d->l2tab[i].refcnt, 0);
|
atomic_set(&d->l2tab[i].refcnt, 0);
|
||||||
|
skb_queue_head_init(&d->l2tab[i].arpq);
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@ -715,7 +699,8 @@ static char l2e_state(const struct l2t_entry *e)
|
|||||||
case L2T_STATE_VALID: return 'V';
|
case L2T_STATE_VALID: return 'V';
|
||||||
case L2T_STATE_STALE: return 'S';
|
case L2T_STATE_STALE: return 'S';
|
||||||
case L2T_STATE_SYNC_WRITE: return 'W';
|
case L2T_STATE_SYNC_WRITE: return 'W';
|
||||||
case L2T_STATE_RESOLVING: return e->arpq_head ? 'A' : 'R';
|
case L2T_STATE_RESOLVING:
|
||||||
|
return skb_queue_empty(&e->arpq) ? 'R' : 'A';
|
||||||
case L2T_STATE_SWITCHING: return 'X';
|
case L2T_STATE_SWITCHING: return 'X';
|
||||||
default:
|
default:
|
||||||
return 'U';
|
return 'U';
|
||||||
|
@ -76,8 +76,7 @@ struct l2t_entry {
|
|||||||
struct neighbour *neigh; /* associated neighbour */
|
struct neighbour *neigh; /* associated neighbour */
|
||||||
struct l2t_entry *first; /* start of hash chain */
|
struct l2t_entry *first; /* start of hash chain */
|
||||||
struct l2t_entry *next; /* next l2t_entry on chain */
|
struct l2t_entry *next; /* next l2t_entry on chain */
|
||||||
struct sk_buff *arpq_head; /* queue of packets awaiting resolution */
|
struct sk_buff_head arpq; /* packet queue awaiting resolution */
|
||||||
struct sk_buff *arpq_tail;
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
atomic_t refcnt; /* entry reference count */
|
atomic_t refcnt; /* entry reference count */
|
||||||
u16 hash; /* hash bucket the entry is on */
|
u16 hash; /* hash bucket the entry is on */
|
||||||
|
Loading…
Reference in New Issue
Block a user