1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds #include <linux/types.h>
31da177e4SLinus Torvalds #include <linux/atmmpc.h>
45a0e3ad6STejun Heo #include <linux/slab.h>
51da177e4SLinus Torvalds #include <linux/time.h>
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include "mpoa_caches.h"
81da177e4SLinus Torvalds #include "mpc.h"
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds /*
111da177e4SLinus Torvalds * mpoa_caches.c: Implementation of ingress and egress cache
121da177e4SLinus Torvalds * handling functions
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds #if 0
16b50c2ea7SJoe Perches #define dprintk(format, args...) \
17b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
181da177e4SLinus Torvalds #else
19bee67d34SJoe Perches #define dprintk(format, args...) \
20b50c2ea7SJoe Perches do { if (0) \
21b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
22b50c2ea7SJoe Perches } while (0)
231da177e4SLinus Torvalds #endif
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #if 0
26b50c2ea7SJoe Perches #define ddprintk(format, args...) \
27b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
281da177e4SLinus Torvalds #else
29bee67d34SJoe Perches #define ddprintk(format, args...) \
30b50c2ea7SJoe Perches do { if (0) \
31b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
32b50c2ea7SJoe Perches } while (0)
331da177e4SLinus Torvalds #endif
341da177e4SLinus Torvalds
in_cache_get(__be32 dst_ip,struct mpoa_client * client)3530d492daSAl Viro static in_cache_entry *in_cache_get(__be32 dst_ip,
361da177e4SLinus Torvalds struct mpoa_client *client)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds in_cache_entry *entry;
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock);
411da177e4SLinus Torvalds entry = client->in_cache;
421da177e4SLinus Torvalds while (entry != NULL) {
431da177e4SLinus Torvalds if (entry->ctrl_info.in_dst_ip == dst_ip) {
4493714912SReshetova, Elena refcount_inc(&entry->use);
451da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
461da177e4SLinus Torvalds return entry;
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds entry = entry->next;
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds return NULL;
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds
in_cache_get_with_mask(__be32 dst_ip,struct mpoa_client * client,__be32 mask)5530d492daSAl Viro static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
561da177e4SLinus Torvalds struct mpoa_client *client,
5730d492daSAl Viro __be32 mask)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds in_cache_entry *entry;
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock);
621da177e4SLinus Torvalds entry = client->in_cache;
631da177e4SLinus Torvalds while (entry != NULL) {
641da177e4SLinus Torvalds if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) {
6593714912SReshetova, Elena refcount_inc(&entry->use);
661da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
671da177e4SLinus Torvalds return entry;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds entry = entry->next;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds return NULL;
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds
in_cache_get_by_vcc(struct atm_vcc * vcc,struct mpoa_client * client)771da177e4SLinus Torvalds static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
781da177e4SLinus Torvalds struct mpoa_client *client)
791da177e4SLinus Torvalds {
801da177e4SLinus Torvalds in_cache_entry *entry;
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock);
831da177e4SLinus Torvalds entry = client->in_cache;
841da177e4SLinus Torvalds while (entry != NULL) {
851da177e4SLinus Torvalds if (entry->shortcut == vcc) {
8693714912SReshetova, Elena refcount_inc(&entry->use);
871da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
881da177e4SLinus Torvalds return entry;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds entry = entry->next;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds return NULL;
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds
in_cache_add_entry(__be32 dst_ip,struct mpoa_client * client)9730d492daSAl Viro static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
981da177e4SLinus Torvalds struct mpoa_client *client)
991da177e4SLinus Torvalds {
1002afe37cdSArnaldo Carvalho de Melo in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL);
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds if (entry == NULL) {
103bee67d34SJoe Perches pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
1041da177e4SLinus Torvalds return NULL;
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds
107b50c2ea7SJoe Perches dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip);
1081da177e4SLinus Torvalds
10993714912SReshetova, Elena refcount_set(&entry->use, 1);
110b50c2ea7SJoe Perches dprintk("new_in_cache_entry: about to lock\n");
1111da177e4SLinus Torvalds write_lock_bh(&client->ingress_lock);
1121da177e4SLinus Torvalds entry->next = client->in_cache;
1131da177e4SLinus Torvalds entry->prev = NULL;
1141da177e4SLinus Torvalds if (client->in_cache != NULL)
1151da177e4SLinus Torvalds client->in_cache->prev = entry;
1161da177e4SLinus Torvalds client->in_cache = entry;
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
1191da177e4SLinus Torvalds entry->ctrl_info.in_dst_ip = dst_ip;
120d750dbdcSTina Ruchandani entry->time = ktime_get_seconds();
1211da177e4SLinus Torvalds entry->retry_time = client->parameters.mpc_p4;
1221da177e4SLinus Torvalds entry->count = 1;
1231da177e4SLinus Torvalds entry->entry_state = INGRESS_INVALID;
1241da177e4SLinus Torvalds entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT;
12593714912SReshetova, Elena refcount_inc(&entry->use);
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds write_unlock_bh(&client->ingress_lock);
128b50c2ea7SJoe Perches dprintk("new_in_cache_entry: unlocked\n");
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds return entry;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
cache_hit(in_cache_entry * entry,struct mpoa_client * mpc)1331da177e4SLinus Torvalds static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds struct atm_mpoa_qos *qos;
1361da177e4SLinus Torvalds struct k_message msg;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds entry->count++;
1391da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
1401da177e4SLinus Torvalds return OPEN;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds if (entry->entry_state == INGRESS_REFRESHING) {
1431da177e4SLinus Torvalds if (entry->count > mpc->parameters.mpc_p1) {
1441da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RQST;
1451da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info;
1461da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
1471da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
148bee67d34SJoe Perches if (qos != NULL)
149bee67d34SJoe Perches msg.qos = qos->qos;
1501da177e4SLinus Torvalds msg_to_mpoad(&msg, mpc);
151d750dbdcSTina Ruchandani entry->reply_wait = ktime_get_seconds();
1521da177e4SLinus Torvalds entry->entry_state = INGRESS_RESOLVING;
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds if (entry->shortcut != NULL)
1551da177e4SLinus Torvalds return OPEN;
1561da177e4SLinus Torvalds return CLOSED;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
1601da177e4SLinus Torvalds return OPEN;
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds if (entry->count > mpc->parameters.mpc_p1 &&
1631da177e4SLinus Torvalds entry->entry_state == INGRESS_INVALID) {
164b50c2ea7SJoe Perches dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n",
16521454aaaSHarvey Harrison mpc->dev->name, &entry->ctrl_info.in_dst_ip);
1661da177e4SLinus Torvalds entry->entry_state = INGRESS_RESOLVING;
1671da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RQST;
1681da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
1691da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info;
1701da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
171bee67d34SJoe Perches if (qos != NULL)
172bee67d34SJoe Perches msg.qos = qos->qos;
1731da177e4SLinus Torvalds msg_to_mpoad(&msg, mpc);
174d750dbdcSTina Ruchandani entry->reply_wait = ktime_get_seconds();
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds return CLOSED;
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds
in_cache_put(in_cache_entry * entry)1801da177e4SLinus Torvalds static void in_cache_put(in_cache_entry *entry)
1811da177e4SLinus Torvalds {
18293714912SReshetova, Elena if (refcount_dec_and_test(&entry->use)) {
183*453431a5SWaiman Long kfree_sensitive(entry);
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds /*
1881da177e4SLinus Torvalds * This should be called with write lock on
1891da177e4SLinus Torvalds */
in_cache_remove_entry(in_cache_entry * entry,struct mpoa_client * client)1901da177e4SLinus Torvalds static void in_cache_remove_entry(in_cache_entry *entry,
1911da177e4SLinus Torvalds struct mpoa_client *client)
1921da177e4SLinus Torvalds {
1931da177e4SLinus Torvalds struct atm_vcc *vcc;
1941da177e4SLinus Torvalds struct k_message msg;
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds vcc = entry->shortcut;
197b50c2ea7SJoe Perches dprintk("removing an ingress entry, ip = %pI4\n",
19821454aaaSHarvey Harrison &entry->ctrl_info.in_dst_ip);
1991da177e4SLinus Torvalds
2001da177e4SLinus Torvalds if (entry->prev != NULL)
2011da177e4SLinus Torvalds entry->prev->next = entry->next;
2021da177e4SLinus Torvalds else
2031da177e4SLinus Torvalds client->in_cache = entry->next;
2041da177e4SLinus Torvalds if (entry->next != NULL)
2051da177e4SLinus Torvalds entry->next->prev = entry->prev;
2061da177e4SLinus Torvalds client->in_ops->put(entry);
2071da177e4SLinus Torvalds if (client->in_cache == NULL && client->eg_cache == NULL) {
2081da177e4SLinus Torvalds msg.type = STOP_KEEP_ALIVE_SM;
2091da177e4SLinus Torvalds msg_to_mpoad(&msg, client);
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds /* Check if the egress side still uses this VCC */
2131da177e4SLinus Torvalds if (vcc != NULL) {
214bee67d34SJoe Perches eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc,
215bee67d34SJoe Perches client);
2161da177e4SLinus Torvalds if (eg_entry != NULL) {
2171da177e4SLinus Torvalds client->eg_ops->put(eg_entry);
2181da177e4SLinus Torvalds return;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds vcc_release_async(vcc, -EPIPE);
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds /* Call this every MPC-p2 seconds... Not exactly correct solution,
2251da177e4SLinus Torvalds but an easy one... */
clear_count_and_expired(struct mpoa_client * client)2261da177e4SLinus Torvalds static void clear_count_and_expired(struct mpoa_client *client)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds in_cache_entry *entry, *next_entry;
229d750dbdcSTina Ruchandani time64_t now;
2301da177e4SLinus Torvalds
231d750dbdcSTina Ruchandani now = ktime_get_seconds();
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds write_lock_bh(&client->ingress_lock);
2341da177e4SLinus Torvalds entry = client->in_cache;
2351da177e4SLinus Torvalds while (entry != NULL) {
2361da177e4SLinus Torvalds entry->count = 0;
2371da177e4SLinus Torvalds next_entry = entry->next;
238d750dbdcSTina Ruchandani if ((now - entry->time) > entry->ctrl_info.holding_time) {
239b50c2ea7SJoe Perches dprintk("holding time expired, ip = %pI4\n",
24021454aaaSHarvey Harrison &entry->ctrl_info.in_dst_ip);
2411da177e4SLinus Torvalds client->in_ops->remove_entry(entry, client);
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds entry = next_entry;
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds write_unlock_bh(&client->ingress_lock);
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds
2481da177e4SLinus Torvalds /* Call this every MPC-p4 seconds. */
check_resolving_entries(struct mpoa_client * client)2491da177e4SLinus Torvalds static void check_resolving_entries(struct mpoa_client *client)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds
2521da177e4SLinus Torvalds struct atm_mpoa_qos *qos;
2531da177e4SLinus Torvalds in_cache_entry *entry;
254d750dbdcSTina Ruchandani time64_t now;
2551da177e4SLinus Torvalds struct k_message msg;
2561da177e4SLinus Torvalds
257d750dbdcSTina Ruchandani now = ktime_get_seconds();
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock);
2601da177e4SLinus Torvalds entry = client->in_cache;
2611da177e4SLinus Torvalds while (entry != NULL) {
2621da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVING) {
263d750dbdcSTina Ruchandani
264d750dbdcSTina Ruchandani if ((now - entry->hold_down)
265d750dbdcSTina Ruchandani < client->parameters.mpc_p6) {
2661da177e4SLinus Torvalds entry = entry->next; /* Entry in hold down */
2671da177e4SLinus Torvalds continue;
2681da177e4SLinus Torvalds }
269d750dbdcSTina Ruchandani if ((now - entry->reply_wait) > entry->retry_time) {
2701da177e4SLinus Torvalds entry->retry_time = MPC_C1 * (entry->retry_time);
271bee67d34SJoe Perches /*
272bee67d34SJoe Perches * Retry time maximum exceeded,
273bee67d34SJoe Perches * put entry in hold down.
274bee67d34SJoe Perches */
2751da177e4SLinus Torvalds if (entry->retry_time > client->parameters.mpc_p5) {
276d750dbdcSTina Ruchandani entry->hold_down = ktime_get_seconds();
2771da177e4SLinus Torvalds entry->retry_time = client->parameters.mpc_p4;
2781da177e4SLinus Torvalds entry = entry->next;
2791da177e4SLinus Torvalds continue;
2801da177e4SLinus Torvalds }
2811da177e4SLinus Torvalds /* Ask daemon to send a resolution request. */
282d750dbdcSTina Ruchandani memset(&entry->hold_down, 0, sizeof(time64_t));
2831da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RTRY;
2841da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
2851da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info;
2861da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
287bee67d34SJoe Perches if (qos != NULL)
288bee67d34SJoe Perches msg.qos = qos->qos;
2891da177e4SLinus Torvalds msg_to_mpoad(&msg, client);
290d750dbdcSTina Ruchandani entry->reply_wait = ktime_get_seconds();
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds entry = entry->next;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds /* Call this every MPC-p5 seconds. */
refresh_entries(struct mpoa_client * client)2991da177e4SLinus Torvalds static void refresh_entries(struct mpoa_client *client)
3001da177e4SLinus Torvalds {
301d750dbdcSTina Ruchandani time64_t now;
3021da177e4SLinus Torvalds struct in_cache_entry *entry = client->in_cache;
3031da177e4SLinus Torvalds
304b50c2ea7SJoe Perches ddprintk("refresh_entries\n");
305d750dbdcSTina Ruchandani now = ktime_get_seconds();
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock);
3081da177e4SLinus Torvalds while (entry != NULL) {
3091da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVED) {
3101da177e4SLinus Torvalds if (!(entry->refresh_time))
3111da177e4SLinus Torvalds entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3;
312d750dbdcSTina Ruchandani if ((now - entry->reply_wait) >
313bee67d34SJoe Perches entry->refresh_time) {
314b50c2ea7SJoe Perches dprintk("refreshing an entry.\n");
3151da177e4SLinus Torvalds entry->entry_state = INGRESS_REFRESHING;
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds entry = entry->next;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock);
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds
in_destroy_cache(struct mpoa_client * mpc)3241da177e4SLinus Torvalds static void in_destroy_cache(struct mpoa_client *mpc)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds write_lock_irq(&mpc->ingress_lock);
3271da177e4SLinus Torvalds while (mpc->in_cache != NULL)
3281da177e4SLinus Torvalds mpc->in_ops->remove_entry(mpc->in_cache, mpc);
3291da177e4SLinus Torvalds write_unlock_irq(&mpc->ingress_lock);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds
eg_cache_get_by_cache_id(__be32 cache_id,struct mpoa_client * mpc)332bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id,
333bee67d34SJoe Perches struct mpoa_client *mpc)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds eg_cache_entry *entry;
3361da177e4SLinus Torvalds
3371da177e4SLinus Torvalds read_lock_irq(&mpc->egress_lock);
3381da177e4SLinus Torvalds entry = mpc->eg_cache;
3391da177e4SLinus Torvalds while (entry != NULL) {
3401da177e4SLinus Torvalds if (entry->ctrl_info.cache_id == cache_id) {
341e00bdbefSReshetova, Elena refcount_inc(&entry->use);
3421da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock);
3431da177e4SLinus Torvalds return entry;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds entry = entry->next;
3461da177e4SLinus Torvalds }
3471da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock);
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds return NULL;
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds /* This can be called from any context since it saves CPU flags */
eg_cache_get_by_tag(__be32 tag,struct mpoa_client * mpc)35330d492daSAl Viro static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
3541da177e4SLinus Torvalds {
3551da177e4SLinus Torvalds unsigned long flags;
3561da177e4SLinus Torvalds eg_cache_entry *entry;
3571da177e4SLinus Torvalds
3581da177e4SLinus Torvalds read_lock_irqsave(&mpc->egress_lock, flags);
3591da177e4SLinus Torvalds entry = mpc->eg_cache;
3601da177e4SLinus Torvalds while (entry != NULL) {
3611da177e4SLinus Torvalds if (entry->ctrl_info.tag == tag) {
362e00bdbefSReshetova, Elena refcount_inc(&entry->use);
3631da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags);
3641da177e4SLinus Torvalds return entry;
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds entry = entry->next;
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags);
3691da177e4SLinus Torvalds
3701da177e4SLinus Torvalds return NULL;
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds /* This can be called from any context since it saves CPU flags */
eg_cache_get_by_vcc(struct atm_vcc * vcc,struct mpoa_client * mpc)374bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc,
375bee67d34SJoe Perches struct mpoa_client *mpc)
3761da177e4SLinus Torvalds {
3771da177e4SLinus Torvalds unsigned long flags;
3781da177e4SLinus Torvalds eg_cache_entry *entry;
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds read_lock_irqsave(&mpc->egress_lock, flags);
3811da177e4SLinus Torvalds entry = mpc->eg_cache;
3821da177e4SLinus Torvalds while (entry != NULL) {
3831da177e4SLinus Torvalds if (entry->shortcut == vcc) {
384e00bdbefSReshetova, Elena refcount_inc(&entry->use);
3851da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags);
3861da177e4SLinus Torvalds return entry;
3871da177e4SLinus Torvalds }
3881da177e4SLinus Torvalds entry = entry->next;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags);
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds return NULL;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
eg_cache_get_by_src_ip(__be32 ipaddr,struct mpoa_client * mpc)395bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr,
396bee67d34SJoe Perches struct mpoa_client *mpc)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds eg_cache_entry *entry;
3991da177e4SLinus Torvalds
4001da177e4SLinus Torvalds read_lock_irq(&mpc->egress_lock);
4011da177e4SLinus Torvalds entry = mpc->eg_cache;
4021da177e4SLinus Torvalds while (entry != NULL) {
4031da177e4SLinus Torvalds if (entry->latest_ip_addr == ipaddr) {
404e00bdbefSReshetova, Elena refcount_inc(&entry->use);
4051da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock);
4061da177e4SLinus Torvalds return entry;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds entry = entry->next;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock);
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds return NULL;
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds
eg_cache_put(eg_cache_entry * entry)4151da177e4SLinus Torvalds static void eg_cache_put(eg_cache_entry *entry)
4161da177e4SLinus Torvalds {
417e00bdbefSReshetova, Elena if (refcount_dec_and_test(&entry->use)) {
418*453431a5SWaiman Long kfree_sensitive(entry);
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds /*
4231da177e4SLinus Torvalds * This should be called with write lock on
4241da177e4SLinus Torvalds */
eg_cache_remove_entry(eg_cache_entry * entry,struct mpoa_client * client)4251da177e4SLinus Torvalds static void eg_cache_remove_entry(eg_cache_entry *entry,
4261da177e4SLinus Torvalds struct mpoa_client *client)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds struct atm_vcc *vcc;
4291da177e4SLinus Torvalds struct k_message msg;
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds vcc = entry->shortcut;
432b50c2ea7SJoe Perches dprintk("removing an egress entry.\n");
4331da177e4SLinus Torvalds if (entry->prev != NULL)
4341da177e4SLinus Torvalds entry->prev->next = entry->next;
4351da177e4SLinus Torvalds else
4361da177e4SLinus Torvalds client->eg_cache = entry->next;
4371da177e4SLinus Torvalds if (entry->next != NULL)
4381da177e4SLinus Torvalds entry->next->prev = entry->prev;
4391da177e4SLinus Torvalds client->eg_ops->put(entry);
4401da177e4SLinus Torvalds if (client->in_cache == NULL && client->eg_cache == NULL) {
4411da177e4SLinus Torvalds msg.type = STOP_KEEP_ALIVE_SM;
4421da177e4SLinus Torvalds msg_to_mpoad(&msg, client);
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds /* Check if the ingress side still uses this VCC */
4461da177e4SLinus Torvalds if (vcc != NULL) {
4471da177e4SLinus Torvalds in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client);
4481da177e4SLinus Torvalds if (in_entry != NULL) {
4491da177e4SLinus Torvalds client->in_ops->put(in_entry);
4501da177e4SLinus Torvalds return;
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds vcc_release_async(vcc, -EPIPE);
4531da177e4SLinus Torvalds }
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds
eg_cache_add_entry(struct k_message * msg,struct mpoa_client * client)456bee67d34SJoe Perches static eg_cache_entry *eg_cache_add_entry(struct k_message *msg,
457bee67d34SJoe Perches struct mpoa_client *client)
4581da177e4SLinus Torvalds {
4592afe37cdSArnaldo Carvalho de Melo eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL);
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds if (entry == NULL) {
462bee67d34SJoe Perches pr_info("out of memory\n");
4631da177e4SLinus Torvalds return NULL;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds
466b50c2ea7SJoe Perches dprintk("adding an egress entry, ip = %pI4, this should be our IP\n",
46721454aaaSHarvey Harrison &msg->content.eg_info.eg_dst_ip);
4681da177e4SLinus Torvalds
469e00bdbefSReshetova, Elena refcount_set(&entry->use, 1);
470b50c2ea7SJoe Perches dprintk("new_eg_cache_entry: about to lock\n");
4711da177e4SLinus Torvalds write_lock_irq(&client->egress_lock);
4721da177e4SLinus Torvalds entry->next = client->eg_cache;
4731da177e4SLinus Torvalds entry->prev = NULL;
4741da177e4SLinus Torvalds if (client->eg_cache != NULL)
4751da177e4SLinus Torvalds client->eg_cache->prev = entry;
4761da177e4SLinus Torvalds client->eg_cache = entry;
4771da177e4SLinus Torvalds
4781da177e4SLinus Torvalds memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
4791da177e4SLinus Torvalds entry->ctrl_info = msg->content.eg_info;
480d750dbdcSTina Ruchandani entry->time = ktime_get_seconds();
4811da177e4SLinus Torvalds entry->entry_state = EGRESS_RESOLVED;
482b50c2ea7SJoe Perches dprintk("new_eg_cache_entry cache_id %u\n",
483bee67d34SJoe Perches ntohl(entry->ctrl_info.cache_id));
484b50c2ea7SJoe Perches dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip);
485e00bdbefSReshetova, Elena refcount_inc(&entry->use);
4861da177e4SLinus Torvalds
4871da177e4SLinus Torvalds write_unlock_irq(&client->egress_lock);
488b50c2ea7SJoe Perches dprintk("new_eg_cache_entry: unlocked\n");
4891da177e4SLinus Torvalds
4901da177e4SLinus Torvalds return entry;
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds
update_eg_cache_entry(eg_cache_entry * entry,uint16_t holding_time)4931da177e4SLinus Torvalds static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time)
4941da177e4SLinus Torvalds {
495d750dbdcSTina Ruchandani entry->time = ktime_get_seconds();
4961da177e4SLinus Torvalds entry->entry_state = EGRESS_RESOLVED;
4971da177e4SLinus Torvalds entry->ctrl_info.holding_time = holding_time;
4981da177e4SLinus Torvalds }
4991da177e4SLinus Torvalds
clear_expired(struct mpoa_client * client)5001da177e4SLinus Torvalds static void clear_expired(struct mpoa_client *client)
5011da177e4SLinus Torvalds {
5021da177e4SLinus Torvalds eg_cache_entry *entry, *next_entry;
503d750dbdcSTina Ruchandani time64_t now;
5041da177e4SLinus Torvalds struct k_message msg;
5051da177e4SLinus Torvalds
506d750dbdcSTina Ruchandani now = ktime_get_seconds();
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds write_lock_irq(&client->egress_lock);
5091da177e4SLinus Torvalds entry = client->eg_cache;
5101da177e4SLinus Torvalds while (entry != NULL) {
5111da177e4SLinus Torvalds next_entry = entry->next;
512d750dbdcSTina Ruchandani if ((now - entry->time) > entry->ctrl_info.holding_time) {
5131da177e4SLinus Torvalds msg.type = SND_EGRESS_PURGE;
5141da177e4SLinus Torvalds msg.content.eg_info = entry->ctrl_info;
515b50c2ea7SJoe Perches dprintk("egress_cache: holding time expired, cache_id = %u.\n",
516bee67d34SJoe Perches ntohl(entry->ctrl_info.cache_id));
5171da177e4SLinus Torvalds msg_to_mpoad(&msg, client);
5181da177e4SLinus Torvalds client->eg_ops->remove_entry(entry, client);
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds entry = next_entry;
5211da177e4SLinus Torvalds }
5221da177e4SLinus Torvalds write_unlock_irq(&client->egress_lock);
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds
eg_destroy_cache(struct mpoa_client * mpc)5251da177e4SLinus Torvalds static void eg_destroy_cache(struct mpoa_client *mpc)
5261da177e4SLinus Torvalds {
5271da177e4SLinus Torvalds write_lock_irq(&mpc->egress_lock);
5281da177e4SLinus Torvalds while (mpc->eg_cache != NULL)
5291da177e4SLinus Torvalds mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
5301da177e4SLinus Torvalds write_unlock_irq(&mpc->egress_lock);
5311da177e4SLinus Torvalds }
5321da177e4SLinus Torvalds
5331da177e4SLinus Torvalds
5344dd191bbSJulia Lawall static const struct in_cache_ops ingress_ops = {
53599a5e178SKees Cook .add_entry = in_cache_add_entry,
53699a5e178SKees Cook .get = in_cache_get,
53799a5e178SKees Cook .get_with_mask = in_cache_get_with_mask,
53899a5e178SKees Cook .get_by_vcc = in_cache_get_by_vcc,
53999a5e178SKees Cook .put = in_cache_put,
54099a5e178SKees Cook .remove_entry = in_cache_remove_entry,
54199a5e178SKees Cook .cache_hit = cache_hit,
54299a5e178SKees Cook .clear_count = clear_count_and_expired,
54399a5e178SKees Cook .check_resolving = check_resolving_entries,
54499a5e178SKees Cook .refresh = refresh_entries,
54599a5e178SKees Cook .destroy_cache = in_destroy_cache
5461da177e4SLinus Torvalds };
5471da177e4SLinus Torvalds
5484dd191bbSJulia Lawall static const struct eg_cache_ops egress_ops = {
54999a5e178SKees Cook .add_entry = eg_cache_add_entry,
55099a5e178SKees Cook .get_by_cache_id = eg_cache_get_by_cache_id,
55199a5e178SKees Cook .get_by_tag = eg_cache_get_by_tag,
55299a5e178SKees Cook .get_by_vcc = eg_cache_get_by_vcc,
55399a5e178SKees Cook .get_by_src_ip = eg_cache_get_by_src_ip,
55499a5e178SKees Cook .put = eg_cache_put,
55599a5e178SKees Cook .remove_entry = eg_cache_remove_entry,
55699a5e178SKees Cook .update = update_eg_cache_entry,
55799a5e178SKees Cook .clear_expired = clear_expired,
55899a5e178SKees Cook .destroy_cache = eg_destroy_cache
5591da177e4SLinus Torvalds };
5601da177e4SLinus Torvalds
atm_mpoa_init_cache(struct mpoa_client * mpc)5611da177e4SLinus Torvalds void atm_mpoa_init_cache(struct mpoa_client *mpc)
5621da177e4SLinus Torvalds {
5631da177e4SLinus Torvalds mpc->in_ops = &ingress_ops;
5641da177e4SLinus Torvalds mpc->eg_ops = &egress_ops;
5651da177e4SLinus Torvalds }
566