diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2014-07-05 10:14:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-08 18:30:11 -0400 |
commit | b37cccf031bdcaba2f461cdb5a2b93ebbd0af03c (patch) | |
tree | a7b05f482ba6835c23ad01772d018c53ee780763 /drivers/net/fddi | |
parent | a630be70771ddbe8253f619ac4b9ca4c3277b13b (diff) |
defxx: Handle DMA mapping errors
This adds error handling for DMA mapping requests; I think there isn't
much else to say about it.
A good side-effect is the mapping in the transmit path is now made with
the board lock released. Also if DMA mapping fails for a newly
allocated receive buffer, then data from the old buffer will be copied
out (as is presently done for small frames only whose size does not
exceed SKBUFF_RX_COPYBREAK) and the original buffer returned, with its
mapping unchanged, to the DMA descriptor ring.
Reported-by: Robert Coerver <Robert.Coerver@ll.mit.edu>
Tested-by: Robert Coerver <Robert.Coerver@ll.mit.edu>
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fddi')
-rw-r--r-- | drivers/net/fddi/defxx.c | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 4c5a2fe67dfb..ed23288d1c55 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c | |||
@@ -2923,21 +2923,35 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) | |||
2923 | for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) | 2923 | for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) |
2924 | for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) | 2924 | for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) |
2925 | { | 2925 | { |
2926 | struct sk_buff *newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, GFP_NOIO); | 2926 | struct sk_buff *newskb; |
2927 | dma_addr_t dma_addr; | ||
2928 | |||
2929 | newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, | ||
2930 | GFP_NOIO); | ||
2927 | if (!newskb) | 2931 | if (!newskb) |
2928 | return -ENOMEM; | 2932 | return -ENOMEM; |
2929 | bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | | ||
2930 | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); | ||
2931 | /* | 2933 | /* |
2932 | * align to 128 bytes for compatibility with | 2934 | * align to 128 bytes for compatibility with |
2933 | * the old EISA boards. | 2935 | * the old EISA boards. |
2934 | */ | 2936 | */ |
2935 | 2937 | ||
2936 | my_skb_align(newskb, 128); | 2938 | my_skb_align(newskb, 128); |
2939 | dma_addr = dma_map_single(bp->bus_dev, | ||
2940 | newskb->data, | ||
2941 | PI_RCV_DATA_K_SIZE_MAX, | ||
2942 | DMA_FROM_DEVICE); | ||
2943 | if (dma_mapping_error(bp->bus_dev, dma_addr)) { | ||
2944 | dev_kfree_skb(newskb); | ||
2945 | return -ENOMEM; | ||
2946 | } | ||
2947 | bp->descr_block_virt->rcv_data[i + j].long_0 = | ||
2948 | (u32)(PI_RCV_DESCR_M_SOP | | ||
2949 | ((PI_RCV_DATA_K_SIZE_MAX / | ||
2950 | PI_ALIGN_K_RCV_DATA_BUFF) << | ||
2951 | PI_RCV_DESCR_V_SEG_LEN)); | ||
2937 | bp->descr_block_virt->rcv_data[i + j].long_1 = | 2952 | bp->descr_block_virt->rcv_data[i + j].long_1 = |
2938 | (u32)dma_map_single(bp->bus_dev, newskb->data, | 2953 | (u32)dma_addr; |
2939 | PI_RCV_DATA_K_SIZE_MAX, | 2954 | |
2940 | DMA_FROM_DEVICE); | ||
2941 | /* | 2955 | /* |
2942 | * p_rcv_buff_va is only used inside the | 2956 | * p_rcv_buff_va is only used inside the |
2943 | * kernel so we put the skb pointer here. | 2957 | * kernel so we put the skb pointer here. |
@@ -3004,7 +3018,7 @@ static void dfx_rcv_queue_process( | |||
3004 | PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ | 3018 | PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ |
3005 | char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ | 3019 | char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ |
3006 | u32 descr, pkt_len; /* FMC descriptor field and packet length */ | 3020 | u32 descr, pkt_len; /* FMC descriptor field and packet length */ |
3007 | struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ | 3021 | struct sk_buff *skb = NULL; /* pointer to a sk_buff to hold incoming packet data */ |
3008 | 3022 | ||
3009 | /* Service all consumed LLC receive frames */ | 3023 | /* Service all consumed LLC receive frames */ |
3010 | 3024 | ||
@@ -3042,15 +3056,30 @@ static void dfx_rcv_queue_process( | |||
3042 | bp->rcv_length_errors++; | 3056 | bp->rcv_length_errors++; |
3043 | else{ | 3057 | else{ |
3044 | #ifdef DYNAMIC_BUFFERS | 3058 | #ifdef DYNAMIC_BUFFERS |
3059 | struct sk_buff *newskb = NULL; | ||
3060 | |||
3045 | if (pkt_len > SKBUFF_RX_COPYBREAK) { | 3061 | if (pkt_len > SKBUFF_RX_COPYBREAK) { |
3046 | struct sk_buff *newskb; | 3062 | dma_addr_t new_dma_addr; |
3047 | 3063 | ||
3048 | newskb = netdev_alloc_skb(bp->dev, | 3064 | newskb = netdev_alloc_skb(bp->dev, |
3049 | NEW_SKB_SIZE); | 3065 | NEW_SKB_SIZE); |
3050 | if (newskb){ | 3066 | if (newskb){ |
3067 | my_skb_align(newskb, 128); | ||
3068 | new_dma_addr = dma_map_single( | ||
3069 | bp->bus_dev, | ||
3070 | newskb->data, | ||
3071 | PI_RCV_DATA_K_SIZE_MAX, | ||
3072 | DMA_FROM_DEVICE); | ||
3073 | if (dma_mapping_error( | ||
3074 | bp->bus_dev, | ||
3075 | new_dma_addr)) { | ||
3076 | dev_kfree_skb(newskb); | ||
3077 | newskb = NULL; | ||
3078 | } | ||
3079 | } | ||
3080 | if (newskb) { | ||
3051 | rx_in_place = 1; | 3081 | rx_in_place = 1; |
3052 | 3082 | ||
3053 | my_skb_align(newskb, 128); | ||
3054 | skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; | 3083 | skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; |
3055 | dma_unmap_single(bp->bus_dev, | 3084 | dma_unmap_single(bp->bus_dev, |
3056 | bp->descr_block_virt->rcv_data[entry].long_1, | 3085 | bp->descr_block_virt->rcv_data[entry].long_1, |
@@ -3058,14 +3087,10 @@ static void dfx_rcv_queue_process( | |||
3058 | DMA_FROM_DEVICE); | 3087 | DMA_FROM_DEVICE); |
3059 | skb_reserve(skb, RCV_BUFF_K_PADDING); | 3088 | skb_reserve(skb, RCV_BUFF_K_PADDING); |
3060 | bp->p_rcv_buff_va[entry] = (char *)newskb; | 3089 | bp->p_rcv_buff_va[entry] = (char *)newskb; |
3061 | bp->descr_block_virt->rcv_data[entry].long_1 = | 3090 | bp->descr_block_virt->rcv_data[entry].long_1 = (u32)new_dma_addr; |
3062 | (u32)dma_map_single(bp->bus_dev, | 3091 | } |
3063 | newskb->data, | 3092 | } |
3064 | PI_RCV_DATA_K_SIZE_MAX, | 3093 | if (!newskb) |
3065 | DMA_FROM_DEVICE); | ||
3066 | } else | ||
3067 | skb = NULL; | ||
3068 | } else | ||
3069 | #endif | 3094 | #endif |
3070 | /* Alloc new buffer to pass up, | 3095 | /* Alloc new buffer to pass up, |
3071 | * add room for PRH. */ | 3096 | * add room for PRH. */ |
@@ -3185,6 +3210,7 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, | |||
3185 | u8 prod; /* local transmit producer index */ | 3210 | u8 prod; /* local transmit producer index */ |
3186 | PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ | 3211 | PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ |
3187 | XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ | 3212 | XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ |
3213 | dma_addr_t dma_addr; | ||
3188 | unsigned long flags; | 3214 | unsigned long flags; |
3189 | 3215 | ||
3190 | netif_stop_queue(dev); | 3216 | netif_stop_queue(dev); |
@@ -3232,6 +3258,20 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, | |||
3232 | } | 3258 | } |
3233 | } | 3259 | } |
3234 | 3260 | ||
3261 | /* Write the three PRH bytes immediately before the FC byte */ | ||
3262 | |||
3263 | skb_push(skb, 3); | ||
3264 | skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ | ||
3265 | skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ | ||
3266 | skb->data[2] = DFX_PRH2_BYTE; /* specification */ | ||
3267 | |||
3268 | dma_addr = dma_map_single(bp->bus_dev, skb->data, skb->len, | ||
3269 | DMA_TO_DEVICE); | ||
3270 | if (dma_mapping_error(bp->bus_dev, dma_addr)) { | ||
3271 | skb_pull(skb, 3); | ||
3272 | return NETDEV_TX_BUSY; | ||
3273 | } | ||
3274 | |||
3235 | spin_lock_irqsave(&bp->lock, flags); | 3275 | spin_lock_irqsave(&bp->lock, flags); |
3236 | 3276 | ||
3237 | /* Get the current producer and the next free xmt data descriptor */ | 3277 | /* Get the current producer and the next free xmt data descriptor */ |
@@ -3252,13 +3292,6 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, | |||
3252 | 3292 | ||
3253 | p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ | 3293 | p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ |
3254 | 3294 | ||
3255 | /* Write the three PRH bytes immediately before the FC byte */ | ||
3256 | |||
3257 | skb_push(skb,3); | ||
3258 | skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ | ||
3259 | skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ | ||
3260 | skb->data[2] = DFX_PRH2_BYTE; /* specification */ | ||
3261 | |||
3262 | /* | 3295 | /* |
3263 | * Write the descriptor with buffer info and bump producer | 3296 | * Write the descriptor with buffer info and bump producer |
3264 | * | 3297 | * |
@@ -3287,8 +3320,7 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, | |||
3287 | */ | 3320 | */ |
3288 | 3321 | ||
3289 | p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); | 3322 | p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); |
3290 | p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, | 3323 | p_xmt_descr->long_1 = (u32)dma_addr; |
3291 | skb->len, DMA_TO_DEVICE); | ||
3292 | 3324 | ||
3293 | /* | 3325 | /* |
3294 | * Verify that descriptor is actually available | 3326 | * Verify that descriptor is actually available |